Towards NV path rendering

Review URL: http://codereview.appspot.com/6302049/



git-svn-id: http://skia.googlecode.com/svn/trunk@4219 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2012-06-11 15:36:13 +00:00
parent f8a2289667
commit 64aef2bacd
14 changed files with 289 additions and 29 deletions

View File

@ -241,6 +241,7 @@
'../src/gpu/GrInOrderDrawBuffer.h',
'../src/gpu/GrMatrix.cpp',
'../src/gpu/GrMemory.cpp',
'../src/gpu/GrPath.h',
'../src/gpu/GrPathRendererChain.cpp',
'../src/gpu/GrPathRendererChain.h',
'../src/gpu/GrPathRenderer.cpp',
@ -295,6 +296,8 @@
'../src/gpu/gl/GrGLIndexBuffer.h',
'../src/gpu/gl/GrGLInterface.cpp',
'../src/gpu/gl/GrGLIRect.h',
'../src/gpu/gl/GrGLPath.cpp',
'../src/gpu/gl/GrGLPath.h',
'../src/gpu/gl/GrGLProgram.cpp',
'../src/gpu/gl/GrGLProgram.h',
'../src/gpu/gl/GrGLProgramStage.cpp',

View File

@ -14,6 +14,7 @@
#include "GrRefCnt.h"
#include "GrSamplerState.h"
#include "GrStencil.h"
#include "GrTexture.h"
#include "SkXfermode.h"

View File

@ -830,6 +830,14 @@ void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
}
}
void GrDrawTarget::stencilPath(const GrPath& path, GrPathFill fill) {
// TODO: extract portions of checkDraw that are relevant to path stenciling.
GrAssert(fCaps.fPathStencilingSupport);
GrAssert(kHairLine_GrPathFill != fill);
GrAssert(!GrIsFillInverted(fill));
this->onStencilPath(path, fill);
}
////////////////////////////////////////////////////////////////////////////////
// Some blend modes allow folding a partial coverage value into the color's

View File

@ -12,22 +12,17 @@
#define GrDrawTarget_DEFINED
#include "GrClip.h"
#include "GrColor.h"
#include "GrDrawState.h"
#include "GrIndexBuffer.h"
#include "GrMatrix.h"
#include "GrRefCnt.h"
#include "GrSamplerState.h"
#include "GrStencil.h"
#include "GrTexture.h"
#include "SkXfermode.h"
#include "SkTLazy.h"
class GrTexture;
class GrClipIterator;
class GrPath;
class GrVertexBuffer;
class GrIndexBuffer;
class GrDrawTarget : public GrRefCnt {
public:
@ -52,6 +47,7 @@ public:
bool fFSAASupport : 1;
bool fDualSourceBlendingSupport : 1;
bool fBufferLockSupport : 1;
bool fPathStencilingSupport : 1;
int fMaxRenderTargetSize;
int fMaxTextureSize;
};
@ -436,7 +432,7 @@ public:
* Pops the vertex / index sources from the matching push.
*/
void popGeometrySource();
/**
* Draws indexed geometry using the current state and current vertex / index
* sources.
@ -469,6 +465,13 @@ public:
int startVertex,
int vertexCount);
/**
* Draws path into the stencil buffer. The fill must be either even/odd or
* 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& path, GrPathFill fill);
/**
* Helper function for drawing rects. This does not use the current index
* and vertex sources. After returning, the vertex and index sources may
@ -1042,6 +1045,8 @@ protected:
virtual void onDrawNonIndexed(GrPrimitiveType type,
int startVertex,
int vertexCount) = 0;
virtual void onStencilPath(const GrPath& path, GrPathFill fill) = 0;
// subclass overrides to be notified when clip is set. Must call
// INHERITED::clipwillBeSet
virtual void clipWillBeSet(const GrClip& clip) {}

View File

@ -226,6 +226,12 @@ GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
return this->onCreateIndexBuffer(size, dynamic);
}
GrPath* GrGpu::createPath(const SkPath& path) {
GrAssert(fCaps.fPathStencilingSupport);
this->handleDirtyContext();
return this->onCreatePath(path);
}
void GrGpu::clear(const GrIRect* rect, GrColor color) {
if (NULL == this->getDrawState().getRenderTarget()) {
return;
@ -358,7 +364,7 @@ const GrStencilSettings* GrGpu::GetClipStencilSettings(void) {
////////////////////////////////////////////////////////////////////////////////
bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
bool GrGpu::setupClipAndFlushState(DrawType type) {
ScissoringSettings scissoringSettings;
@ -410,7 +416,7 @@ void GrGpu::onDrawIndexed(GrPrimitiveType type,
this->handleDirtyContext();
if (!this->setupClipAndFlushState(type)) {
if (!this->setupClipAndFlushState(PrimTypeToDrawType(type))) {
return;
}
@ -423,11 +429,11 @@ void GrGpu::onDrawIndexed(GrPrimitiveType type,
}
void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
int startVertex,
int vertexCount) {
int startVertex,
int vertexCount) {
this->handleDirtyContext();
if (!this->setupClipAndFlushState(type)) {
if (!this->setupClipAndFlushState(PrimTypeToDrawType(type))) {
return;
}
@ -437,6 +443,16 @@ void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
}
void GrGpu::onStencilPath(const GrPath& path, GrPathFill fill) {
this->handleDirtyContext();
if (!this->setupClipAndFlushState(kStencilPath_DrawType)) {
return;
}
this->onGpuStencilPath(path, fill);
}
void GrGpu::finalizeReservedVertices() {
GrAssert(NULL != fVertexPool);
fVertexPool->unlock();

View File

@ -13,11 +13,11 @@
#include "GrDrawTarget.h"
#include "GrRect.h"
#include "GrRefCnt.h"
#include "GrTexture.h"
#include "GrClipMaskManager.h"
class GrContext;
class GrIndexBufferAllocPool;
class GrPath;
class GrPathRenderer;
class GrPathRendererChain;
class GrResource;
@ -129,6 +129,12 @@ public:
*/
GrIndexBuffer* createIndexBuffer(uint32_t size, bool dynamic);
/**
* 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);
/**
* Returns an index buffer that can be used to render quads.
* Six indices per quad: 0, 1, 2, 0, 2, 3, etc.
@ -341,8 +347,32 @@ public:
}
protected:
enum DrawType {
kDrawPoints_DrawType,
kDrawLines_DrawType,
kDrawTriangles_DrawType,
kStencilPath_DrawType,
};
DrawType PrimTypeToDrawType(GrPrimitiveType type) {
switch (type) {
case kTriangles_GrPrimitiveType:
case kTriangleStrip_GrPrimitiveType:
case kTriangleFan_GrPrimitiveType:
return kDrawTriangles_DrawType;
case kPoints_GrPrimitiveType:
return kDrawPoints_DrawType;
case kLines_GrPrimitiveType:
case kLineStrip_GrPrimitiveType:
return kDrawLines_DrawType;
default:
GrCrash("Unexpected primitive type");
return kDrawTriangles_DrawType;
}
}
// prepares clip flushes gpu state before a draw
bool setupClipAndFlushState(GrPrimitiveType type);
bool setupClipAndFlushState(DrawType);
// Functions used to map clip-respecting stencil tests into normal
// stencil funcs supported by GPUs.
@ -413,6 +443,7 @@ protected:
bool dynamic) = 0;
virtual GrIndexBuffer* onCreateIndexBuffer(uint32_t size,
bool dynamic) = 0;
virtual GrPath* onCreatePath(const SkPath& path) = 0;
// overridden by API-specific derivated class to perform the clear and
// clearRect. NULL rect means clear whole target.
@ -428,6 +459,8 @@ protected:
virtual void onGpuDrawNonIndexed(GrPrimitiveType type,
uint32_t vertexCount,
uint32_t numVertices) = 0;
// overridden by API-specific derived class to perform the path stenciling.
virtual void onGpuStencilPath(const GrPath& path, GrPathFill fill) = 0;
// overridden by API-specific derived class to perform flush
virtual void onForceRenderTargetFlush() = 0;
@ -472,7 +505,7 @@ protected:
// deltas from previous state at draw time. This function does the
// API-specific flush of the state
// returns false if current state is unsupported.
virtual bool flushGraphicsState(GrPrimitiveType type) = 0;
virtual bool flushGraphicsState(DrawType) = 0;
// clears the entire stencil buffer to 0
virtual void clearStencil() = 0;
@ -518,6 +551,7 @@ private:
virtual void onDrawNonIndexed(GrPrimitiveType type,
int startVertex,
int vertexCount) SK_OVERRIDE;
virtual void onStencilPath(const GrPath& path, GrPathFill fill) SK_OVERRIDE;
// readies the pools to provide vertex/index data.
void prepareVertexPool();

View File

@ -439,6 +439,10 @@ void GrInOrderDrawBuffer::onDrawNonIndexed(GrPrimitiveType primitiveType,
draw.fIndexBuffer = NULL;
}
void GrInOrderDrawBuffer::onStencilPath(const GrPath&, GrPathFill) {
GrCrash("Not implemented yet. Should not get here.");
}
void GrInOrderDrawBuffer::clear(const GrIRect* rect, GrColor color) {
GrIRect r;
if (NULL == rect) {

View File

@ -147,6 +147,7 @@ private:
virtual void onDrawNonIndexed(GrPrimitiveType primitiveType,
int startVertex,
int vertexCount) SK_OVERRIDE;
virtual void onStencilPath(const GrPath&, GrPathFill) SK_OVERRIDE;
virtual bool onReserveVertexSpace(GrVertexLayout layout,
int vertexCount,
void** vertices) SK_OVERRIDE;

28
src/gpu/GrPath.h Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrPath_DEFINED
#define GrPath_DEFINED
#include "GrResource.h"
#include "GrRect.h"
class GrPath : public GrResource {
public:
GrPath(GrGpu* gpu) : INHERITED(gpu) {}
const GrIRect& getBounds() const { return fBounds; }
protected:
GrIRect fBounds;
private:
typedef GrResource INHERITED;
};
#endif

101
src/gpu/gl/GrGLPath.cpp Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrGLPath.h"
#include "GrGpuGL.h"
#define GPUGL static_cast<GrGpuGL*>(this->getGpu())
#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
#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) {
static const GrGLubyte gTable[] = {
GR_GL_MOVE_TO,
GR_GL_LINE_TO,
GR_GL_QUADRATIC_CURVE_TO,
GR_GL_CUBIC_CURVE_TO,
GR_GL_CLOSE_PATH,
};
GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
GR_STATIC_ASSERT(3 == SkPath::kCubic_Verb);
GR_STATIC_ASSERT(4 == SkPath::kClose_Verb);
GrAssert(verb >= 0 && verb < GR_ARRAY_COUNT(gTable));
return gTable[verb];
}
inline int num_pts(const SkPath::Verb verb) {
static const int gTable[] = {
1, // move
1, // line
2, // quad
3, // cubic
0, // close
};
GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
GR_STATIC_ASSERT(3 == SkPath::kCubic_Verb);
GR_STATIC_ASSERT(4 == SkPath::kClose_Verb);
GrAssert(verb >= 0 && verb < GR_ARRAY_COUNT(gTable));
return gTable[verb];
}
}
GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path) : INHERITED(gpu) {
GL_CALL_RET(fPathID, GenPaths(1));
SkPath::Iter iter(path, true);
SkSTArray<16, GrGLubyte, true> pathCommands;
GR_STATIC_ASSERT(SK_SCALAR_IS_FLOAT); // assuming SkPoint is floats
SkSTArray<16, SkPoint, true> pathPoints;
int verbCnt = path.countVerbs();
int pointCnt = path.countPoints();
pathCommands.resize_back(verbCnt);
pathPoints.resize_back(pointCnt);
// TODO: Direct access to path points since we could pass them on directly.
path.getPoints(&pathPoints[0], pointCnt);
path.getVerbs(&pathCommands[0], verbCnt);
GR_DEBUGCODE(int numPts = 0);
for (int i = 0; i < verbCnt; ++i) {
SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]);
pathCommands[i] = verb_to_gl_path_cmd(v);
GR_DEBUGCODE(numPts += num_pts(v));
}
GrAssert(pathPoints.count() == numPts);
GL_CALL(PathCommands(fPathID,
verbCnt, &pathCommands[0],
2 * pointCnt, GR_GL_FLOAT, &pathPoints[0]));
GrRect bounds = path.getBounds();
bounds.roundOut(&fBounds);
}
GrGLPath::~GrGLPath() {
this->release();
}
void GrGLPath::onRelease() {
if (0 != fPathID) {
GL_CALL(DeletePaths(1, fPathID));
fPathID = 0;
}
}
void GrGLPath::onAbandon() {
fPathID = 0;
}

43
src/gpu/gl/GrGLPath.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrGLPath_DEFINED
#define GrGLPath_DEFINED
#include "../GrPath.h"
#include "gl/GrGLFunctions.h"
class GrGpuGL;
class SkPath;
/**
* Currently this represents a path built using GL_NV_path_rendering. If we
* support other GL path extensions then this would have to have a type enum
* and/or be subclassed.
*/
class GrGLPath : public GrPath {
public:
GrGLPath(GrGpuGL* gpu, const SkPath& path);
virtual ~GrGLPath();
GrGLuint pathID() const { return fPathID; }
// TODO: Figure out how to get an approximate size of the path in Gpu
// memory.
virtual size_t sizeInBytes() const SK_OVERRIDE { return 100; }
protected:
virtual void onRelease() SK_OVERRIDE;
virtual void onAbandon() SK_OVERRIDE;
private:
GrGLuint fPathID;
typedef GrPath INHERITED;
};
#endif

View File

@ -8,6 +8,7 @@
#include "GrGpuGL.h"
#include "GrGLStencilBuffer.h"
#include "GrGLPath.h"
#include "GrTypes.h"
#include "SkTemplates.h"
@ -1325,6 +1326,14 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
return NULL;
}
GrPath* GrGpuGL::onCreatePath(const SkPath& inPath) {
GrPath* path = NULL;
if (fCaps.fPathStencilingSupport) {
path = new GrGLPath(this, inPath);
}
return path;
}
void GrGpuGL::enableScissoring(const GrIRect& rect) {
const GrDrawState& drawState = this->getDrawState();
const GrGLRenderTarget* rt =
@ -1718,6 +1727,10 @@ void GrGpuGL::onGpuDrawNonIndexed(GrPrimitiveType type,
#endif
}
void GrGpuGL::onGpuStencilPath(const GrPath&, GrPathFill) {
GrCrash("Not implemented yet. Should not get here.");
}
void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
@ -1955,7 +1968,7 @@ void GrGpuGL::flushStencil() {
}
}
void GrGpuGL::flushAAState(GrPrimitiveType type) {
void GrGpuGL::flushAAState(bool isLines) {
const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
if (kDesktop_GrGLBinding == this->glBinding()) {
// ES doesn't support toggling GL_MULTISAMPLE and doesn't have
@ -1963,7 +1976,7 @@ void GrGpuGL::flushAAState(GrPrimitiveType type) {
// we prefer smooth lines over multisampled lines
bool smoothLines = false;
if (GrIsPrimTypeLines(type)) {
if (isLines) {
smoothLines = this->willUseHWAALines();
if (smoothLines) {
if (kYes_TriState != fHWAAState.fSmoothLineEnabled) {
@ -1999,10 +2012,10 @@ void GrGpuGL::flushAAState(GrPrimitiveType type) {
}
}
void GrGpuGL::flushBlend(GrPrimitiveType type,
void GrGpuGL::flushBlend(bool isLines,
GrBlendCoeff srcCoeff,
GrBlendCoeff dstCoeff) {
if (GrIsPrimTypeLines(type) && this->willUseHWAALines()) {
if (isLines && this->willUseHWAALines()) {
if (kYes_TriState != fHWBlendState.fEnabled) {
GL_CALL(Enable(GR_GL_BLEND));
fHWBlendState.fEnabled = kYes_TriState;

View File

@ -67,6 +67,7 @@ protected:
bool dynamic) SK_OVERRIDE;
virtual GrIndexBuffer* onCreateIndexBuffer(uint32_t size,
bool dynamic) SK_OVERRIDE;
virtual GrPath* onCreatePath(const SkPath&) SK_OVERRIDE;
virtual GrTexture* onCreatePlatformTexture(
const GrPlatformTextureDesc& desc) SK_OVERRIDE;
virtual GrRenderTarget* onCreatePlatformRenderTarget(
@ -106,13 +107,14 @@ protected:
virtual void onGpuDrawNonIndexed(GrPrimitiveType type,
uint32_t vertexCount,
uint32_t numVertices) SK_OVERRIDE;
virtual void onGpuStencilPath(const GrPath&, GrPathFill) SK_OVERRIDE;
virtual void enableScissoring(const GrIRect& rect) SK_OVERRIDE;
virtual void disableScissor() SK_OVERRIDE;
virtual void clearStencil() SK_OVERRIDE;
virtual void clearStencilClip(const GrIRect& rect,
bool insideClip) SK_OVERRIDE;
virtual bool flushGraphicsState(GrPrimitiveType type) SK_OVERRIDE;
virtual bool flushGraphicsState(DrawType) SK_OVERRIDE;
virtual void setupGeometry(int* startVertex,
int* startIndex,
int vertexCount,
@ -135,7 +137,7 @@ private:
// The params should be the final coeffecients to apply
// (after any blending optimizations or dual source blending considerations
// have been accounted for).
void flushBlend(GrPrimitiveType type,
void flushBlend(bool isLines,
GrBlendCoeff srcCoeff,
GrBlendCoeff dstCoeff);
@ -233,7 +235,7 @@ private:
static void DeleteProgram(const GrGLInterface* gl,
CachedData* programData);
void buildProgram(GrPrimitiveType typeBlend,
void buildProgram(bool isPoints,
BlendOptFlags blendOpts,
GrBlendCoeff dstCoeff,
GrCustomStage** customStages);
@ -261,7 +263,7 @@ private:
// NULL means whole target. Can be an empty rect.
void flushRenderTarget(const GrIRect* bound);
void flushStencil();
void flushAAState(GrPrimitiveType type);
void flushAAState(bool isLines);
bool configToGLFormats(GrPixelConfig config,
bool getSizedInternal,

View File

@ -370,7 +370,7 @@ void GrGpuGL::flushCoverage(GrColor coverage) {
}
}
bool GrGpuGL::flushGraphicsState(GrPrimitiveType type) {
bool GrGpuGL::flushGraphicsState(DrawType type) {
const GrDrawState& drawState = this->getDrawState();
// GrGpu::setupClipAndFlushState should have already checked this
@ -379,7 +379,7 @@ bool GrGpuGL::flushGraphicsState(GrPrimitiveType type) {
this->flushMiscFixedFunctionState();
this->flushStencil();
this->flushAAState(type);
this->flushAAState(kDrawLines_DrawType == type);
GrBlendCoeff srcCoeff;
GrBlendCoeff dstCoeff;
@ -389,7 +389,8 @@ bool GrGpuGL::flushGraphicsState(GrPrimitiveType type) {
}
GrCustomStage* customStages [GrDrawState::kNumStages];
this->buildProgram(type, blendOpts, dstCoeff, customStages);
this->buildProgram(kDrawPoints_DrawType == type,
blendOpts, dstCoeff, customStages);
fProgramData = fProgramCache->getProgramData(fCurrentProgram,
customStages);
if (NULL == fProgramData) {
@ -402,7 +403,7 @@ bool GrGpuGL::flushGraphicsState(GrPrimitiveType type) {
fHWProgramID = fProgramData->fProgramID;
}
fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
this->flushBlend(type, srcCoeff, dstCoeff);
this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff);
GrColor color;
GrColor coverage;
@ -635,7 +636,7 @@ void setup_custom_stage(GrGLProgram::ProgramDesc::StageDesc* stage,
}
void GrGpuGL::buildProgram(GrPrimitiveType type,
void GrGpuGL::buildProgram(bool isPoints,
BlendOptFlags blendOpts,
GrBlendCoeff dstCoeff,
GrCustomStage** customStages) {
@ -658,7 +659,7 @@ void GrGpuGL::buildProgram(GrPrimitiveType type,
// Must initialize all fields or cache will have false negatives!
desc.fVertexLayout = this->getVertexLayout();
desc.fEmitsPointSize = kPoints_GrPrimitiveType == type;
desc.fEmitsPointSize = isPoints;
bool requiresAttributeColors =
!skipColor && SkToBool(desc.fVertexLayout & kColor_VertexLayoutBit);