aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-11-01 15:23:44 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-11-01 15:23:44 +0000
commit5c8ee2539b9316b22416a991a1f560ef5cec7957 (patch)
treeebd654235f81028533a630e9ae35617c03b78cb6
parente1e99ef0af69fef21f2897621e7dfc5257da7ce7 (diff)
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
-rw-r--r--include/core/SkStrokeRec.h8
-rw-r--r--include/gpu/GrContext.h11
-rw-r--r--src/gpu/GrContext.cpp17
-rw-r--r--src/gpu/GrPath.cpp23
-rw-r--r--src/gpu/GrPath.h17
-rw-r--r--src/gpu/GrStencilAndCoverPathRenderer.cpp4
-rw-r--r--src/gpu/gl/GrGLPath.cpp12
-rw-r--r--src/gpu/gl/GrGLPath.h2
8 files changed, 80 insertions, 14 deletions
diff --git a/include/core/SkStrokeRec.h b/include/core/SkStrokeRec.h
index c5b47c25dd..1e0ec880f7 100644
--- a/include/core/SkStrokeRec.h
+++ b/include/core/SkStrokeRec.h
@@ -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;
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index ba3e53a48f..f302a44808 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -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;
};
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 7887add232..b0d34fd039 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -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 {
diff --git a/src/gpu/GrPath.cpp b/src/gpu/GrPath.cpp
index afd223902f..f928dffaa8 100644
--- a/src/gpu/GrPath.cpp
+++ b/src/gpu/GrPath.cpp
@@ -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);
+}
diff --git a/src/gpu/GrPath.h b/src/gpu/GrPath.h
index 37dc9591a6..f481ea4286 100644
--- a/src/gpu/GrPath.h
+++ b/src/gpu/GrPath.h
@@ -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;
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.cpp b/src/gpu/GrStencilAndCoverPathRenderer.cpp
index 0271b22a9a..273c01b861 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/GrStencilAndCoverPathRenderer.cpp
@@ -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,
diff --git a/src/gpu/gl/GrGLPath.cpp b/src/gpu/gl/GrGLPath.cpp
index c85644e311..a749e410bd 100644
--- a/src/gpu/gl/GrGLPath.cpp
+++ b/src/gpu/gl/GrGLPath.cpp
@@ -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())));
diff --git a/src/gpu/gl/GrGLPath.h b/src/gpu/gl/GrGLPath.h
index ef3aa567ad..3647d4d628 100644
--- a/src/gpu/gl/GrGLPath.h
+++ b/src/gpu/gl/GrGLPath.h
@@ -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