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(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(stroke.getMiter()); + keyData[3] = static_cast(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 p(fGpu->createPath(path, stroke)); + SkAutoTUnref 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 p(fGpu->createPath(path, stroke)); + SkAutoTUnref 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(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