Make GrContext cache the gpu paths
Creating paths for nv_path_rendering is costly. Try to reduce this cost by caching paths based on the SkPath "hash" (i.e. SkPathRef generation id) and stroke properties. Adds the paths to GrContext::fTextureCache instance. Later this should be renamed and the GrContext API should reflect the nature of the cache better. R=bsalomon@google.com, mtklein@google.com Author: kkinnunen@nvidia.com Review URL: https://codereview.chromium.org/26557003 git-svn-id: http://skia.googlecode.com/svn/trunk@12083 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
e1e99ef0af
commit
5c8ee2539b
@ -81,6 +81,14 @@ public:
|
||||
*/
|
||||
bool applyToPath(SkPath* dst, const SkPath& src) const;
|
||||
|
||||
bool operator==(const SkStrokeRec& other) const {
|
||||
return fWidth == other.fWidth &&
|
||||
fMiterLimit == other.fMiterLimit &&
|
||||
fCap == other.fCap &&
|
||||
fJoin == other.fJoin &&
|
||||
fStrokeAndFill == other.fStrokeAndFill;
|
||||
}
|
||||
|
||||
private:
|
||||
SkScalar fWidth;
|
||||
SkScalar fMiterLimit;
|
||||
|
@ -29,6 +29,7 @@ class GrIndexBuffer;
|
||||
class GrIndexBufferAllocPool;
|
||||
class GrInOrderDrawBuffer;
|
||||
class GrOvalRenderer;
|
||||
class GrPath;
|
||||
class GrPathRenderer;
|
||||
class GrResourceEntry;
|
||||
class GrResourceCache;
|
||||
@ -925,6 +926,7 @@ private:
|
||||
// Needed so GrTexture's returnToCache helper function can call
|
||||
// addExistingTextureToCache
|
||||
friend class GrTexture;
|
||||
friend class GrStencilAndCoverPathRenderer;
|
||||
|
||||
// Add an existing texture to the texture cache. This is intended solely
|
||||
// for use with textures released from an GrAutoScratchTexture.
|
||||
@ -948,6 +950,15 @@ private:
|
||||
*/
|
||||
static bool OverbudgetCB(void* data);
|
||||
|
||||
/** Creates a new gpu path, based on the specified path and stroke and returns it.
|
||||
* The caller owns a ref on the returned path which must be balanced by a call to unref.
|
||||
*
|
||||
* @param skPath the path geometry.
|
||||
* @param stroke the path stroke.
|
||||
* @return a new path or NULL if the operation is not supported by the backend.
|
||||
*/
|
||||
GrPath* createPath(const SkPath& skPath, const SkStrokeRec& stroke);
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
||||
|
@ -217,6 +217,7 @@ void GrContext::contextDestroyed() {
|
||||
fOvalRenderer->reset();
|
||||
|
||||
fTextureCache->purgeAllUnlocked();
|
||||
|
||||
fFontCache->freeAll();
|
||||
fGpu->markContextDirty();
|
||||
}
|
||||
@ -1813,6 +1814,22 @@ const GrEffectRef* GrContext::createUPMToPMEffect(GrTexture* texture,
|
||||
}
|
||||
}
|
||||
|
||||
GrPath* GrContext::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
|
||||
SkASSERT(fGpu->caps()->pathRenderingSupport());
|
||||
|
||||
// TODO: now we add to fTextureCache. This should change to fResourceCache.
|
||||
GrResourceKey resourceKey = GrPath::ComputeKey(inPath, stroke);
|
||||
GrPath* path = static_cast<GrPath*>(fTextureCache->find(resourceKey));
|
||||
if (NULL != path && path->isEqualTo(inPath, stroke)) {
|
||||
path->ref();
|
||||
} else {
|
||||
path = fGpu->createPath(inPath, stroke);
|
||||
fTextureCache->purgeAsNeeded(1, path->sizeInBytes());
|
||||
fTextureCache->addResource(resourceKey, path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#if GR_CACHE_STATS
|
||||
void GrContext::printCacheStats() const {
|
||||
|
@ -8,3 +8,26 @@
|
||||
#include "GrPath.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(GrPath)
|
||||
|
||||
GrResourceKey GrPath::ComputeKey(const SkPath& path, const SkStrokeRec& stroke) {
|
||||
static const GrResourceKey::ResourceType gPathResourceType = GrResourceKey::GenerateResourceType();
|
||||
static const GrCacheID::Domain gPathDomain = GrCacheID::GenerateDomain();
|
||||
|
||||
GrCacheID::Key key;
|
||||
uint32_t* keyData = key.fData32;
|
||||
keyData[0] = path.getGenerationID();
|
||||
|
||||
SK_COMPILE_ASSERT(SkPaint::kJoinCount <= 3, cap_shift_will_be_wrong);
|
||||
keyData[1] = stroke.needToApply();
|
||||
if (0 != keyData[1]) {
|
||||
keyData[1] |= stroke.getJoin() << 1;
|
||||
keyData[1] |= stroke.getCap() << 3;
|
||||
keyData[2] = static_cast<uint32_t>(stroke.getMiter());
|
||||
keyData[3] = static_cast<uint32_t>(stroke.getWidth());
|
||||
} else {
|
||||
keyData[2] = 0;
|
||||
keyData[3] = 0;
|
||||
}
|
||||
|
||||
return GrResourceKey(GrCacheID(gPathDomain, key), gPathResourceType, 0);
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
#define GrPath_DEFINED
|
||||
|
||||
#include "GrResource.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkStrokeRec.h"
|
||||
|
||||
@ -16,9 +18,17 @@ class GrPath : public GrResource {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(GrPath);
|
||||
|
||||
GrPath(GrGpu* gpu, bool isWrapped, const SkStrokeRec& stroke)
|
||||
GrPath(GrGpu* gpu, bool isWrapped, const SkPath& skPath, const SkStrokeRec& stroke)
|
||||
: INHERITED(gpu, isWrapped),
|
||||
fStroke(stroke) {
|
||||
fSkPath(skPath),
|
||||
fStroke(stroke),
|
||||
fBounds(skPath.getBounds()) {
|
||||
}
|
||||
|
||||
static GrResourceKey ComputeKey(const SkPath& path, const SkStrokeRec& stroke);
|
||||
|
||||
bool isEqualTo(const SkPath& path, const SkStrokeRec& stroke) {
|
||||
return fSkPath == path && fStroke == stroke;
|
||||
}
|
||||
|
||||
const SkRect& getBounds() const { return fBounds; }
|
||||
@ -26,8 +36,9 @@ public:
|
||||
const SkStrokeRec& getStroke() const { return fStroke; }
|
||||
|
||||
protected:
|
||||
SkRect fBounds;
|
||||
SkPath fSkPath;
|
||||
SkStrokeRec fStroke;
|
||||
SkRect fBounds;
|
||||
|
||||
private:
|
||||
typedef GrResource INHERITED;
|
||||
|
@ -55,7 +55,7 @@ void GrStencilAndCoverPathRenderer::onStencilPath(const SkPath& path,
|
||||
const SkStrokeRec& stroke,
|
||||
GrDrawTarget* target) {
|
||||
SkASSERT(!path.isInverseFillType());
|
||||
SkAutoTUnref<GrPath> p(fGpu->createPath(path, stroke));
|
||||
SkAutoTUnref<GrPath> p(fGpu->getContext()->createPath(path, stroke));
|
||||
target->stencilPath(p, path.getFillType());
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path,
|
||||
GrDrawState* drawState = target->drawState();
|
||||
SkASSERT(drawState->getStencil().isDisabled());
|
||||
|
||||
SkAutoTUnref<GrPath> p(fGpu->createPath(path, stroke));
|
||||
SkAutoTUnref<GrPath> p(fGpu->getContext()->createPath(path, stroke));
|
||||
|
||||
if (path.isInverseFillType()) {
|
||||
GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include "GrGLPath.h"
|
||||
#include "GrGpuGL.h"
|
||||
#include "SkStrokeRec.h"
|
||||
|
||||
#define GPUGL static_cast<GrGpuGL*>(this->getGpu())
|
||||
|
||||
@ -87,7 +86,7 @@ inline GrGLenum cap_to_gl_cap(SkPaint::Cap cap) {
|
||||
static const bool kIsWrapped = false; // The constructor creates the GL path object.
|
||||
|
||||
GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke)
|
||||
: INHERITED(gpu, kIsWrapped, stroke) {
|
||||
: INHERITED(gpu, kIsWrapped, path, stroke) {
|
||||
#ifndef SK_SCALAR_IS_FLOAT
|
||||
GrCrash("Assumes scalar is float.");
|
||||
#endif
|
||||
@ -98,14 +97,14 @@ GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke)
|
||||
SkSTArray<16, GrGLubyte, true> pathCommands;
|
||||
SkSTArray<16, SkPoint, true> pathPoints;
|
||||
|
||||
int verbCnt = path.countVerbs();
|
||||
int pointCnt = path.countPoints();
|
||||
int verbCnt = fSkPath.countVerbs();
|
||||
int pointCnt = fSkPath.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);
|
||||
fSkPath.getPoints(&pathPoints[0], pointCnt);
|
||||
fSkPath.getVerbs(&pathCommands[0], verbCnt);
|
||||
|
||||
SkDEBUGCODE(int numPts = 0);
|
||||
for (int i = 0; i < verbCnt; ++i) {
|
||||
@ -118,7 +117,6 @@ GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke)
|
||||
GL_CALL(PathCommands(fPathID,
|
||||
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())));
|
||||
|
@ -13,8 +13,6 @@
|
||||
#include "gl/GrGLFunctions.h"
|
||||
|
||||
class GrGpuGL;
|
||||
class SkPath;
|
||||
class SkStrokeRec;
|
||||
|
||||
/**
|
||||
* Currently this represents a path built using GL_NV_path_rendering. If we
|
||||
|
Loading…
Reference in New Issue
Block a user