Implement stroking a path with nv_path_rendering
Initialize the path stroke properties in the GrGLPath constructor. Use StencilStrokePath and CoverStrokePath to stroke the path. The order of the GL calls is: 1. StencilFill, if needed 2. StencilStroke, if needed 2a. CoverStroke, if stroke was applied 2b. CoverFill, if stroke was not applied The reason for not pairing StencilFill + CoverFill, StencilStroke + CoverStroke is that Skia API does not allow separate fill and stroke color within one call. Covering the stroke bounding box should also cover the fill bounding box. Causes different rendering in gm/dashcubics due to different rendering algorithm. (?) (TODO: this should be resolved somehow.) R=bsalomon@google.com, markkilgard@gmail.com, cdalton@nvidia.com Author: kkinnunen@nvidia.com Review URL: https://codereview.chromium.org/23440049 git-svn-id: http://skia.googlecode.com/svn/trunk@11672 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
598cf5d3cf
commit
32184d8162
@ -517,20 +517,18 @@ void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
|
||||
}
|
||||
}
|
||||
|
||||
void GrDrawTarget::stencilPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill) {
|
||||
void GrDrawTarget::stencilPath(const GrPath* path, SkPath::FillType fill) {
|
||||
// TODO: extract portions of checkDraw that are relevant to path stenciling.
|
||||
SkASSERT(NULL != path);
|
||||
SkASSERT(this->caps()->pathRenderingSupport());
|
||||
SkASSERT(!stroke.isHairlineStyle());
|
||||
SkASSERT(!SkPath::IsInverseFillType(fill));
|
||||
this->onStencilPath(path, stroke, fill);
|
||||
this->onStencilPath(path, fill);
|
||||
}
|
||||
|
||||
void GrDrawTarget::fillPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill) {
|
||||
void GrDrawTarget::drawPath(const GrPath* path, SkPath::FillType fill) {
|
||||
// TODO: extract portions of checkDraw that are relevant to path rendering.
|
||||
SkASSERT(NULL != path);
|
||||
SkASSERT(this->caps()->pathRenderingSupport());
|
||||
SkASSERT(!stroke.isHairlineStyle());
|
||||
const GrDrawState* drawState = &getDrawState();
|
||||
|
||||
SkRect devBounds;
|
||||
@ -548,7 +546,7 @@ void GrDrawTarget::fillPath(const GrPath* path, const SkStrokeRec& stroke, SkPat
|
||||
return;
|
||||
}
|
||||
|
||||
this->onFillPath(path, stroke, fill, dstCopy.texture() ? &dstCopy : NULL);
|
||||
this->onDrawPath(path, fill, dstCopy.texture() ? &dstCopy : NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -326,13 +326,13 @@ public:
|
||||
* winding (not inverse or hairline). It will respect the HW antialias flag
|
||||
* on the draw state (if possible in the 3D API).
|
||||
*/
|
||||
void stencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill);
|
||||
void stencilPath(const GrPath*, SkPath::FillType fill);
|
||||
|
||||
/**
|
||||
* Fills a path. Fill must not be a hairline. It will respect the HW
|
||||
* Draws a path. Fill must not be a hairline. It will respect the HW
|
||||
* antialias flag on the draw state (if possible in the 3D API).
|
||||
*/
|
||||
void fillPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill);
|
||||
void drawPath(const GrPath*, SkPath::FillType fill);
|
||||
|
||||
/**
|
||||
* Helper function for drawing rects. It performs a geometry src push and pop
|
||||
@ -455,11 +455,11 @@ public:
|
||||
void executeDraw(const DrawInfo& info) { this->onDraw(info); }
|
||||
|
||||
/**
|
||||
* For subclass internal use to invoke a call to onFillPath().
|
||||
* For subclass internal use to invoke a call to onDrawPath().
|
||||
*/
|
||||
void executeFillPath(const GrPath* path, const SkStrokeRec& stroke,
|
||||
SkPath::FillType fill, const GrDeviceCoordTexture* dstCopy) {
|
||||
this->onFillPath(path, stroke, fill, dstCopy);
|
||||
void executeDrawPath(const GrPath* path, SkPath::FillType fill,
|
||||
const GrDeviceCoordTexture* dstCopy) {
|
||||
this->onDrawPath(path, fill, dstCopy);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@ -838,8 +838,9 @@ private:
|
||||
const SkMatrix* matrix,
|
||||
const SkRect* localRect,
|
||||
const SkMatrix* localMatrix);
|
||||
virtual void onStencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill) = 0;
|
||||
virtual void onFillPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill,
|
||||
|
||||
virtual void onStencilPath(const GrPath*, SkPath::FillType) = 0;
|
||||
virtual void onDrawPath(const GrPath*, SkPath::FillType,
|
||||
const GrDeviceCoordTexture* dstCopy) = 0;
|
||||
|
||||
// helpers for reserving vertex and index space.
|
||||
|
@ -197,10 +197,10 @@ GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
|
||||
return this->onCreateIndexBuffer(size, dynamic);
|
||||
}
|
||||
|
||||
GrPath* GrGpu::createPath(const SkPath& path) {
|
||||
GrPath* GrGpu::createPath(const SkPath& path, const SkStrokeRec& stroke) {
|
||||
SkASSERT(this->caps()->pathRenderingSupport());
|
||||
this->handleDirtyContext();
|
||||
return this->onCreatePath(path);
|
||||
return this->onCreatePath(path, stroke);
|
||||
}
|
||||
|
||||
void GrGpu::clear(const SkIRect* rect,
|
||||
@ -382,7 +382,7 @@ void GrGpu::onDraw(const DrawInfo& info) {
|
||||
this->onGpuDraw(info);
|
||||
}
|
||||
|
||||
void GrGpu::onStencilPath(const GrPath* path, const SkStrokeRec&, SkPath::FillType fill) {
|
||||
void GrGpu::onStencilPath(const GrPath* path, SkPath::FillType fill) {
|
||||
this->handleDirtyContext();
|
||||
|
||||
GrDrawState::AutoRestoreEffects are;
|
||||
@ -393,18 +393,19 @@ void GrGpu::onStencilPath(const GrPath* path, const SkStrokeRec&, SkPath::FillTy
|
||||
this->onGpuStencilPath(path, fill);
|
||||
}
|
||||
|
||||
void GrGpu::onFillPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill,
|
||||
|
||||
void GrGpu::onDrawPath(const GrPath* path, SkPath::FillType fill,
|
||||
const GrDeviceCoordTexture* dstCopy) {
|
||||
this->handleDirtyContext();
|
||||
|
||||
drawState()->setDefaultVertexAttribs();
|
||||
|
||||
GrDrawState::AutoRestoreEffects are;
|
||||
if (!this->setupClipAndFlushState(kFillPath_DrawType, dstCopy, &are)) {
|
||||
if (!this->setupClipAndFlushState(kDrawPath_DrawType, dstCopy, &are)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->onGpuFillPath(path, fill);
|
||||
this->onGpuDrawPath(path, fill);
|
||||
}
|
||||
|
||||
void GrGpu::finalizeReservedVertices() {
|
||||
|
@ -124,7 +124,7 @@ public:
|
||||
* Creates a path object that can be stenciled using stencilPath(). It is
|
||||
* only legal to call this if the caps report support for path stenciling.
|
||||
*/
|
||||
GrPath* createPath(const SkPath& path);
|
||||
GrPath* createPath(const SkPath& path, const SkStrokeRec& stroke);
|
||||
|
||||
/**
|
||||
* Returns an index buffer that can be used to render quads.
|
||||
@ -343,7 +343,7 @@ protected:
|
||||
kDrawLines_DrawType,
|
||||
kDrawTriangles_DrawType,
|
||||
kStencilPath_DrawType,
|
||||
kFillPath_DrawType,
|
||||
kDrawPath_DrawType,
|
||||
};
|
||||
|
||||
DrawType PrimTypeToDrawType(GrPrimitiveType type) {
|
||||
@ -435,7 +435,7 @@ private:
|
||||
virtual GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) = 0;
|
||||
virtual GrVertexBuffer* onCreateVertexBuffer(uint32_t size, bool dynamic) = 0;
|
||||
virtual GrIndexBuffer* onCreateIndexBuffer(uint32_t size, bool dynamic) = 0;
|
||||
virtual GrPath* onCreatePath(const SkPath& path) = 0;
|
||||
virtual GrPath* onCreatePath(const SkPath& path, const SkStrokeRec&) = 0;
|
||||
|
||||
// overridden by backend-specific derived class to perform the clear and
|
||||
// clearRect. NULL rect means clear whole target.
|
||||
@ -446,7 +446,7 @@ private:
|
||||
|
||||
// overridden by backend-specific derived class to perform the path stenciling.
|
||||
virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) = 0;
|
||||
virtual void onGpuFillPath(const GrPath*, SkPath::FillType) = 0;
|
||||
virtual void onGpuDrawPath(const GrPath*, SkPath::FillType) = 0;
|
||||
|
||||
// overridden by backend-specific derived class to perform flush
|
||||
virtual void onForceRenderTargetFlush() = 0;
|
||||
@ -489,10 +489,8 @@ private:
|
||||
|
||||
// GrDrawTarget overrides
|
||||
virtual void onDraw(const DrawInfo&) SK_OVERRIDE;
|
||||
virtual void onStencilPath(const GrPath* path, const SkStrokeRec& stroke,
|
||||
SkPath::FillType) SK_OVERRIDE;
|
||||
|
||||
virtual void onFillPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType,
|
||||
virtual void onStencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
|
||||
virtual void onDrawPath(const GrPath*, SkPath::FillType,
|
||||
const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE;
|
||||
|
||||
// readies the pools to provide vertex/index data.
|
||||
|
@ -384,11 +384,10 @@ void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) {
|
||||
}
|
||||
}
|
||||
|
||||
GrInOrderDrawBuffer::StencilPath::StencilPath() : fStroke(SkStrokeRec::kFill_InitStyle) {}
|
||||
GrInOrderDrawBuffer::FillPath::FillPath() : fStroke(SkStrokeRec::kFill_InitStyle) {}
|
||||
GrInOrderDrawBuffer::StencilPath::StencilPath() {}
|
||||
GrInOrderDrawBuffer::DrawPath::DrawPath() {}
|
||||
|
||||
void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, const SkStrokeRec& stroke,
|
||||
SkPath::FillType fill) {
|
||||
void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, SkPath::FillType fill) {
|
||||
if (this->needsNewClip()) {
|
||||
this->recordClip();
|
||||
}
|
||||
@ -400,10 +399,9 @@ void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, const SkStrokeRec& s
|
||||
sp->fPath.reset(path);
|
||||
path->ref();
|
||||
sp->fFill = fill;
|
||||
sp->fStroke = stroke;
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::onFillPath(const GrPath* path, const SkStrokeRec& stroke,
|
||||
void GrInOrderDrawBuffer::onDrawPath(const GrPath* path,
|
||||
SkPath::FillType fill, const GrDeviceCoordTexture* dstCopy) {
|
||||
if (this->needsNewClip()) {
|
||||
this->recordClip();
|
||||
@ -412,11 +410,10 @@ void GrInOrderDrawBuffer::onFillPath(const GrPath* path, const SkStrokeRec& stro
|
||||
if (this->needsNewState()) {
|
||||
this->recordState();
|
||||
}
|
||||
FillPath* cp = this->recordFillPath();
|
||||
DrawPath* cp = this->recordDrawPath();
|
||||
cp->fPath.reset(path);
|
||||
path->ref();
|
||||
cp->fFill = fill;
|
||||
cp->fStroke = stroke;
|
||||
if (NULL != dstCopy) {
|
||||
cp->fDstCopy = *dstCopy;
|
||||
}
|
||||
@ -456,7 +453,7 @@ void GrInOrderDrawBuffer::reset() {
|
||||
fCmds.reset();
|
||||
fDraws.reset();
|
||||
fStencilPaths.reset();
|
||||
fFillPaths.reset();
|
||||
fDrawPaths.reset();
|
||||
fStates.reset();
|
||||
fClears.reset();
|
||||
fVertexPool.reset();
|
||||
@ -501,7 +498,7 @@ void GrInOrderDrawBuffer::flush() {
|
||||
int currClear = 0;
|
||||
int currDraw = 0;
|
||||
int currStencilPath = 0;
|
||||
int currFillPath = 0;
|
||||
int currDrawPath = 0;
|
||||
int currCopySurface = 0;
|
||||
|
||||
for (int c = 0; c < numCmds; ++c) {
|
||||
@ -519,15 +516,15 @@ void GrInOrderDrawBuffer::flush() {
|
||||
}
|
||||
case kStencilPath_Cmd: {
|
||||
const StencilPath& sp = fStencilPaths[currStencilPath];
|
||||
fDstGpu->stencilPath(sp.fPath.get(), sp.fStroke, sp.fFill);
|
||||
fDstGpu->stencilPath(sp.fPath.get(), sp.fFill);
|
||||
++currStencilPath;
|
||||
break;
|
||||
}
|
||||
case kFillPath_Cmd: {
|
||||
const FillPath& cp = fFillPaths[currFillPath];
|
||||
fDstGpu->executeFillPath(cp.fPath.get(), cp.fStroke, cp.fFill,
|
||||
case kDrawPath_Cmd: {
|
||||
const DrawPath& cp = fDrawPaths[currDrawPath];
|
||||
fDstGpu->executeDrawPath(cp.fPath.get(), cp.fFill,
|
||||
NULL != cp.fDstCopy.texture() ? &cp.fDstCopy : NULL);
|
||||
++currFillPath;
|
||||
++currDrawPath;
|
||||
break;
|
||||
}
|
||||
case kSetState_Cmd:
|
||||
@ -839,9 +836,9 @@ GrInOrderDrawBuffer::StencilPath* GrInOrderDrawBuffer::recordStencilPath() {
|
||||
return &fStencilPaths.push_back();
|
||||
}
|
||||
|
||||
GrInOrderDrawBuffer::FillPath* GrInOrderDrawBuffer::recordFillPath() {
|
||||
fCmds.push_back(kFillPath_Cmd);
|
||||
return &fFillPaths.push_back();
|
||||
GrInOrderDrawBuffer::DrawPath* GrInOrderDrawBuffer::recordDrawPath() {
|
||||
fCmds.push_back(kDrawPath_Cmd);
|
||||
return &fDrawPaths.push_back();
|
||||
}
|
||||
|
||||
GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear() {
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "GrPath.h"
|
||||
|
||||
#include "SkClipStack.h"
|
||||
#include "SkStrokeRec.h"
|
||||
#include "SkTemplates.h"
|
||||
#include "SkTypes.h"
|
||||
|
||||
@ -87,7 +86,7 @@ private:
|
||||
kSetClip_Cmd = 4,
|
||||
kClear_Cmd = 5,
|
||||
kCopySurface_Cmd = 6,
|
||||
kFillPath_Cmd = 7,
|
||||
kDrawPath_Cmd = 7,
|
||||
};
|
||||
|
||||
class DrawRecord : public DrawInfo {
|
||||
@ -101,15 +100,13 @@ private:
|
||||
StencilPath();
|
||||
|
||||
SkAutoTUnref<const GrPath> fPath;
|
||||
SkStrokeRec fStroke;
|
||||
SkPath::FillType fFill;
|
||||
};
|
||||
|
||||
struct FillPath : public ::SkNoncopyable {
|
||||
FillPath();
|
||||
struct DrawPath : public ::SkNoncopyable {
|
||||
DrawPath();
|
||||
|
||||
SkAutoTUnref<const GrPath> fPath;
|
||||
SkStrokeRec fStroke;
|
||||
SkPath::FillType fFill;
|
||||
GrDeviceCoordTexture fDstCopy;
|
||||
};
|
||||
@ -136,9 +133,11 @@ private:
|
||||
const SkMatrix* matrix,
|
||||
const SkRect* localRect,
|
||||
const SkMatrix* localMatrix) SK_OVERRIDE;
|
||||
virtual void onStencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType) SK_OVERRIDE;
|
||||
virtual void onFillPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType,
|
||||
|
||||
virtual void onStencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
|
||||
virtual void onDrawPath(const GrPath*, SkPath::FillType,
|
||||
const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE;
|
||||
|
||||
virtual bool onReserveVertexSpace(size_t vertexSize,
|
||||
int vertexCount,
|
||||
void** vertices) SK_OVERRIDE;
|
||||
@ -181,7 +180,7 @@ private:
|
||||
void recordClip();
|
||||
DrawRecord* recordDraw(const DrawInfo&);
|
||||
StencilPath* recordStencilPath();
|
||||
FillPath* recordFillPath();
|
||||
DrawPath* recordDrawPath();
|
||||
Clear* recordClear();
|
||||
CopySurface* recordCopySurface();
|
||||
|
||||
@ -190,7 +189,7 @@ private:
|
||||
kCmdPreallocCnt = 32,
|
||||
kDrawPreallocCnt = 8,
|
||||
kStencilPathPreallocCnt = 8,
|
||||
kFillPathPreallocCnt = 8,
|
||||
kDrawPathPreallocCnt = 8,
|
||||
kStatePreallocCnt = 8,
|
||||
kClipPreallocCnt = 8,
|
||||
kClearPreallocCnt = 4,
|
||||
@ -201,7 +200,7 @@ private:
|
||||
SkSTArray<kCmdPreallocCnt, uint8_t, true> fCmds;
|
||||
GrSTAllocator<kDrawPreallocCnt, DrawRecord> fDraws;
|
||||
GrSTAllocator<kStatePreallocCnt, StencilPath> fStencilPaths;
|
||||
GrSTAllocator<kStatePreallocCnt, FillPath> fFillPaths;
|
||||
GrSTAllocator<kStatePreallocCnt, DrawPath> fDrawPaths;
|
||||
GrSTAllocator<kStatePreallocCnt, GrDrawState::DeferredState> fStates;
|
||||
GrSTAllocator<kClearPreallocCnt, Clear> fClears;
|
||||
GrSTAllocator<kCopySurfacePreallocCnt, CopySurface> fCopySurfaces;
|
||||
|
@ -10,17 +10,24 @@
|
||||
|
||||
#include "GrResource.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkStrokeRec.h"
|
||||
|
||||
class GrPath : public GrResource {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(GrPath);
|
||||
|
||||
GrPath(GrGpu* gpu, bool isWrapped) : INHERITED(gpu, isWrapped) {}
|
||||
GrPath(GrGpu* gpu, bool isWrapped, const SkStrokeRec& stroke)
|
||||
: INHERITED(gpu, isWrapped),
|
||||
fStroke(stroke) {
|
||||
}
|
||||
|
||||
const SkRect& getBounds() const { return fBounds; }
|
||||
|
||||
const SkStrokeRec& getStroke() const { return fStroke; }
|
||||
|
||||
protected:
|
||||
SkRect fBounds;
|
||||
SkStrokeRec fStroke;
|
||||
|
||||
private:
|
||||
typedef GrResource INHERITED;
|
||||
|
@ -38,7 +38,7 @@ bool GrStencilAndCoverPathRenderer::canDrawPath(const SkPath& path,
|
||||
const SkStrokeRec& stroke,
|
||||
const GrDrawTarget* target,
|
||||
bool antiAlias) const {
|
||||
return stroke.isFillStyle() &&
|
||||
return !stroke.isHairlineStyle() &&
|
||||
!antiAlias && // doesn't do per-path AA, relies on the target having MSAA
|
||||
NULL != target->getDrawState().getRenderTarget()->getStencilBuffer() &&
|
||||
target->getDrawState().getStencil().isDisabled();
|
||||
@ -55,8 +55,8 @@ void GrStencilAndCoverPathRenderer::onStencilPath(const SkPath& path,
|
||||
const SkStrokeRec& stroke,
|
||||
GrDrawTarget* target) {
|
||||
SkASSERT(!path.isInverseFillType());
|
||||
SkAutoTUnref<GrPath> p(fGpu->createPath(path));
|
||||
target->stencilPath(p, stroke, path.getFillType());
|
||||
SkAutoTUnref<GrPath> p(fGpu->createPath(path, stroke));
|
||||
target->stencilPath(p, path.getFillType());
|
||||
}
|
||||
|
||||
bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path,
|
||||
@ -69,7 +69,7 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path,
|
||||
GrDrawState* drawState = target->drawState();
|
||||
SkASSERT(drawState->getStencil().isDisabled());
|
||||
|
||||
SkAutoTUnref<GrPath> p(fGpu->createPath(path));
|
||||
SkAutoTUnref<GrPath> p(fGpu->createPath(path, stroke));
|
||||
|
||||
if (path.isInverseFillType()) {
|
||||
GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
|
||||
@ -96,7 +96,7 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path,
|
||||
*drawState->stencil() = kStencilPass;
|
||||
}
|
||||
|
||||
target->fillPath(p, stroke, path.getFillType());
|
||||
target->drawPath(p, path.getFillType());
|
||||
|
||||
target->drawState()->stencil()->setDisabled();
|
||||
return true;
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "GrGLPath.h"
|
||||
#include "GrGpuGL.h"
|
||||
#include "SkStrokeRec.h"
|
||||
|
||||
#define GPUGL static_cast<GrGpuGL*>(this->getGpu())
|
||||
|
||||
@ -15,7 +16,7 @@
|
||||
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(GPUGL->glInterface(), R, X)
|
||||
|
||||
namespace {
|
||||
inline GrGLubyte verb_to_gl_path_cmd(const SkPath::Verb verb) {
|
||||
inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) {
|
||||
static const GrGLubyte gTable[] = {
|
||||
GR_GL_MOVE_TO,
|
||||
GR_GL_LINE_TO,
|
||||
@ -35,7 +36,7 @@ inline GrGLubyte verb_to_gl_path_cmd(const SkPath::Verb verb) {
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
inline int num_pts(const SkPath::Verb verb) {
|
||||
inline int num_pts(SkPath::Verb verb) {
|
||||
static const int gTable[] = {
|
||||
1, // move
|
||||
1, // line
|
||||
@ -54,11 +55,39 @@ inline int num_pts(const SkPath::Verb verb) {
|
||||
return gTable[verb];
|
||||
}
|
||||
#endif
|
||||
|
||||
inline GrGLenum join_to_gl_join(SkPaint::Join join) {
|
||||
static GrGLenum gSkJoinsToGrGLJoins[] = {
|
||||
GR_GL_MITER_REVERT,
|
||||
GR_GL_ROUND,
|
||||
GR_GL_BEVEL
|
||||
};
|
||||
return gSkJoinsToGrGLJoins[join];
|
||||
GR_STATIC_ASSERT(0 == SkPaint::kMiter_Join);
|
||||
GR_STATIC_ASSERT(1 == SkPaint::kRound_Join);
|
||||
GR_STATIC_ASSERT(2 == SkPaint::kBevel_Join);
|
||||
GR_STATIC_ASSERT(GR_ARRAY_COUNT(gSkJoinsToGrGLJoins) == SkPaint::kJoinCount);
|
||||
}
|
||||
|
||||
inline GrGLenum cap_to_gl_cap(SkPaint::Cap cap) {
|
||||
static GrGLenum gSkCapsToGrGLCaps[] = {
|
||||
GR_GL_FLAT,
|
||||
GR_GL_ROUND,
|
||||
GR_GL_SQUARE
|
||||
};
|
||||
return gSkCapsToGrGLCaps[cap];
|
||||
GR_STATIC_ASSERT(0 == SkPaint::kButt_Cap);
|
||||
GR_STATIC_ASSERT(1 == SkPaint::kRound_Cap);
|
||||
GR_STATIC_ASSERT(2 == SkPaint::kSquare_Cap);
|
||||
GR_STATIC_ASSERT(GR_ARRAY_COUNT(gSkCapsToGrGLCaps) == SkPaint::kCapCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static const bool kIsWrapped = false; // The constructor creates the GL path object.
|
||||
|
||||
GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path) : INHERITED(gpu, kIsWrapped) {
|
||||
GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke)
|
||||
: INHERITED(gpu, kIsWrapped, stroke) {
|
||||
#ifndef SK_SCALAR_IS_FLOAT
|
||||
GrCrash("Assumes scalar is float.");
|
||||
#endif
|
||||
@ -90,6 +119,19 @@ GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path) : INHERITED(gpu, kIsWrapped
|
||||
verbCnt, &pathCommands[0],
|
||||
2 * pointCnt, GR_GL_FLOAT, &pathPoints[0]));
|
||||
fBounds = path.getBounds();
|
||||
|
||||
if (stroke.needToApply()) {
|
||||
GL_CALL(PathParameterf(fPathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
|
||||
GL_CALL(PathParameterf(fPathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter())));
|
||||
GrGLenum join = join_to_gl_join(stroke.getJoin());
|
||||
GL_CALL(PathParameteri(fPathID, GR_GL_PATH_JOIN_STYLE, join));
|
||||
GrGLenum cap = cap_to_gl_cap(stroke.getCap());
|
||||
GL_CALL(PathParameteri(fPathID, GR_GL_PATH_INITIAL_END_CAP, cap));
|
||||
GL_CALL(PathParameteri(fPathID, GR_GL_PATH_TERMINAL_END_CAP, cap));
|
||||
|
||||
// FIXME: try to account for stroking, without rasterizing the stroke.
|
||||
fBounds.outset(SkScalarToFloat(stroke.getWidth()), SkScalarToFloat(stroke.getWidth()));
|
||||
}
|
||||
}
|
||||
|
||||
GrGLPath::~GrGLPath() {
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
class GrGpuGL;
|
||||
class SkPath;
|
||||
class SkStrokeRec;
|
||||
|
||||
/**
|
||||
* Currently this represents a path built using GL_NV_path_rendering. If we
|
||||
@ -23,7 +24,7 @@ class SkPath;
|
||||
|
||||
class GrGLPath : public GrPath {
|
||||
public:
|
||||
GrGLPath(GrGpuGL* gpu, const SkPath& path);
|
||||
GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke);
|
||||
virtual ~GrGLPath();
|
||||
GrGLuint pathID() const { return fPathID; }
|
||||
// TODO: Figure out how to get an approximate size of the path in Gpu
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "GrGLShaderBuilder.h"
|
||||
#include "GrTemplates.h"
|
||||
#include "GrTypes.h"
|
||||
#include "SkStrokeRec.h"
|
||||
#include "SkTemplates.h"
|
||||
|
||||
static const GrGLuint GR_MAX_GLUINT = ~0U;
|
||||
@ -1276,9 +1277,9 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
|
||||
}
|
||||
}
|
||||
|
||||
GrPath* GrGpuGL::onCreatePath(const SkPath& inPath) {
|
||||
GrPath* GrGpuGL::onCreatePath(const SkPath& inPath, const SkStrokeRec& stroke) {
|
||||
SkASSERT(this->caps()->pathRenderingSupport());
|
||||
return SkNEW_ARGS(GrGLPath, (this, inPath));
|
||||
return SkNEW_ARGS(GrGLPath, (this, inPath, stroke));
|
||||
}
|
||||
|
||||
void GrGpuGL::flushScissor() {
|
||||
@ -1700,7 +1701,7 @@ void GrGpuGL::onGpuStencilPath(const GrPath* path, SkPath::FillType fill) {
|
||||
GL_CALL(StencilFillPath(id, fillMode, writeMask));
|
||||
}
|
||||
|
||||
void GrGpuGL::onGpuFillPath(const GrPath* path, SkPath::FillType fill) {
|
||||
void GrGpuGL::onGpuDrawPath(const GrPath* path, SkPath::FillType fill) {
|
||||
SkASSERT(this->caps()->pathRenderingSupport());
|
||||
|
||||
GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
|
||||
@ -1709,16 +1710,27 @@ void GrGpuGL::onGpuFillPath(const GrPath* path, SkPath::FillType fill) {
|
||||
SkASSERT(!fCurrentProgram->hasVertexShader());
|
||||
|
||||
flushPathStencilSettings(fill);
|
||||
const SkStrokeRec& stroke = path->getStroke();
|
||||
|
||||
SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(fill);
|
||||
SkASSERT(!fHWPathStencilSettings.isTwoSided());
|
||||
GrGLenum fillMode =
|
||||
gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
|
||||
GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
|
||||
|
||||
if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
|
||||
GL_CALL(StencilFillPath(id, fillMode, writeMask));
|
||||
}
|
||||
if (stroke.needToApply()) {
|
||||
GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
|
||||
}
|
||||
|
||||
if (nonInvertedFill == fill) {
|
||||
if (stroke.needToApply()) {
|
||||
GL_CALL(CoverStrokePath(id, GR_GL_BOUNDING_BOX));
|
||||
} else {
|
||||
GL_CALL(CoverFillPath(id, GR_GL_BOUNDING_BOX));
|
||||
}
|
||||
} else {
|
||||
GrDrawState* drawState = this->drawState();
|
||||
GrDrawState::AutoViewMatrixRestore avmr;
|
||||
|
@ -121,7 +121,7 @@ private:
|
||||
bool dynamic) SK_OVERRIDE;
|
||||
virtual GrIndexBuffer* onCreateIndexBuffer(uint32_t size,
|
||||
bool dynamic) SK_OVERRIDE;
|
||||
virtual GrPath* onCreatePath(const SkPath&) SK_OVERRIDE;
|
||||
virtual GrPath* onCreatePath(const SkPath&, const SkStrokeRec&) SK_OVERRIDE;
|
||||
virtual GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&) SK_OVERRIDE;
|
||||
virtual GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) SK_OVERRIDE;
|
||||
virtual bool createStencilBufferForRenderTarget(GrRenderTarget* rt,
|
||||
@ -152,7 +152,7 @@ private:
|
||||
virtual void onGpuDraw(const DrawInfo&) SK_OVERRIDE;
|
||||
|
||||
virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
|
||||
virtual void onGpuFillPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
|
||||
virtual void onGpuDrawPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
|
||||
|
||||
virtual void clearStencil() SK_OVERRIDE;
|
||||
virtual void clearStencilClip(const SkIRect& rect,
|
||||
|
@ -253,7 +253,7 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC
|
||||
return false;
|
||||
}
|
||||
|
||||
SkASSERT(kFillPath_DrawType != type || !fCurrentProgram->hasVertexShader());
|
||||
SkASSERT(kDrawPath_DrawType != type || !fCurrentProgram->hasVertexShader());
|
||||
|
||||
fCurrentProgram.get()->ref();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user