From 5c56af1790f58e24d7e9a887c73637fee9b97b38 Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Wed, 28 Feb 2018 16:37:34 +0000 Subject: Revert "Fission GrAtlasGlyphCache in two" This reverts commit acf17904d6286f2a63a5d895541804d0ea1be646. Reason for revert: Chrome Original change's description: > Fission GrAtlasGlyphCache in two > > This CL splits the old GrAtlasGlyphCache into a GrAtlasGlyphCache and an GrAtlasManager. > > The GrAtlasManager itself is split into a rather limited base class (GrRestrictedAtlasManager) > and the all powerful GrAtlasManager. The GrRestrictedAtlasManager is available at op creation > time and provides access to the proxies backing the atlases. The full GrAtlasManager is > only available at flush time and allows instantiation of the proxies and uploading to them. > > In the DDL world all of the DDL Contexts will receive a GrRestrictedAtlasManager-version of the > GrAtlasManager in the main thread. This future atlas manager will have had all of its > GrDrawOpAtlases created (but not instantiated) so there should be no race conditions. > > Change-Id: I9967d3a4116af50128f390c5039a712b8cd4db08 > Reviewed-on: https://skia-review.googlesource.com/108001 > Commit-Queue: Robert Phillips > Reviewed-by: Jim Van Verth TBR=jvanverth@google.com,bsalomon@google.com,robertphillips@google.com Change-Id: I7c760ea1a9f041a310b96d552aa1497ee5902cd8 No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://skia-review.googlesource.com/111040 Reviewed-by: Robert Phillips Commit-Queue: Robert Phillips --- gn/gpu.gni | 6 +- include/gpu/GrContext.h | 6 +- src/atlastext/SkAtlasTextTarget.cpp | 11 +- src/atlastext/SkInternalAtlasTextContext.cpp | 16 +- src/atlastext/SkInternalAtlasTextContext.h | 4 +- src/gpu/GrContext.cpp | 33 +- src/gpu/GrContextPriv.h | 14 +- src/gpu/GrDrawOpAtlas.cpp | 3 +- src/gpu/GrOpFlushState.cpp | 9 - src/gpu/GrOpFlushState.h | 6 - src/gpu/GrProxyProvider.h | 3 +- src/gpu/ops/GrAtlasTextOp.cpp | 35 +- src/gpu/ops/GrAtlasTextOp.h | 24 +- src/gpu/ops/GrMeshDrawOp.h | 5 - src/gpu/text/GrAtlasGlyphCache.cpp | 489 ++++++++++++++++++++++ src/gpu/text/GrAtlasGlyphCache.h | 270 ++++++++++++ src/gpu/text/GrAtlasManager.cpp | 222 ---------- src/gpu/text/GrAtlasManager.h | 155 ------- src/gpu/text/GrAtlasTextBlob.cpp | 21 +- src/gpu/text/GrAtlasTextBlob.h | 24 +- src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp | 29 +- src/gpu/text/GrAtlasTextContext.cpp | 121 +++--- src/gpu/text/GrAtlasTextContext.h | 27 +- src/gpu/text/GrGlyphCache.cpp | 334 --------------- src/gpu/text/GrGlyphCache.h | 148 ------- src/gpu/text/GrTextUtils.h | 2 +- tests/DrawOpAtlasTest.cpp | 2 +- tools/gpu/GrTest.cpp | 10 +- 28 files changed, 925 insertions(+), 1104 deletions(-) create mode 100644 src/gpu/text/GrAtlasGlyphCache.cpp create mode 100644 src/gpu/text/GrAtlasGlyphCache.h delete mode 100644 src/gpu/text/GrAtlasManager.cpp delete mode 100644 src/gpu/text/GrAtlasManager.h delete mode 100644 src/gpu/text/GrGlyphCache.cpp delete mode 100644 src/gpu/text/GrGlyphCache.h diff --git a/gn/gpu.gni b/gn/gpu.gni index 27a50a9a70..a34e62b6b4 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -392,8 +392,8 @@ skia_gpu_sources = [ "$_src/gpu/effects/GrYUVtoRGBEffect.h", # text - "$_src/gpu/text/GrAtlasManager.cpp", - "$_src/gpu/text/GrAtlasManager.h", + "$_src/gpu/text/GrAtlasGlyphCache.cpp", + "$_src/gpu/text/GrAtlasGlyphCache.h", "$_src/gpu/text/GrAtlasTextBlob.cpp", "$_src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp", "$_src/gpu/text/GrAtlasTextBlob.h", @@ -401,8 +401,6 @@ skia_gpu_sources = [ "$_src/gpu/text/GrAtlasTextContext.h", "$_src/gpu/text/GrDistanceFieldAdjustTable.cpp", "$_src/gpu/text/GrDistanceFieldAdjustTable.h", - "$_src/gpu/text/GrGlyphCache.cpp", - "$_src/gpu/text/GrGlyphCache.h", "$_src/gpu/text/GrTextBlobCache.cpp", "$_src/gpu/text/GrTextBlobCache.h", "$_src/gpu/text/GrTextUtils.cpp", diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h index ff4ec5f677..914983c2ec 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -16,7 +16,7 @@ #include "../private/GrSingleOwner.h" #include "GrContextOptions.h" -class GrAtlasManager; +class GrAtlasGlyphCache; class GrBackendFormat; class GrBackendSemaphore; class GrContextPriv; @@ -25,7 +25,6 @@ class GrDrawingManager; struct GrDrawOpAtlasConfig; class GrFragmentProcessor; struct GrGLInterface; -class GrGlyphCache; class GrGpu; class GrIndexBuffer; struct GrMockOptions; @@ -367,8 +366,7 @@ private: sk_sp fThreadSafeProxy; - GrGlyphCache* fGlyphCache; - GrAtlasManager* fFullAtlasManager; + GrAtlasGlyphCache* fAtlasGlyphCache; std::unique_ptr fTextBlobCache; bool fDisableGpuYUVConversion; diff --git a/src/atlastext/SkAtlasTextTarget.cpp b/src/atlastext/SkAtlasTextTarget.cpp index 9da5fd1e3d..f553ffad96 100644 --- a/src/atlastext/SkAtlasTextTarget.cpp +++ b/src/atlastext/SkAtlasTextTarget.cpp @@ -181,17 +181,20 @@ void GrAtlasTextOp::finalizeForTextTarget(uint32_t color, const GrCaps& caps) { void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target) { FlushInfo flushInfo; - SkAutoGlyphCache autoGlyphCache; + SkAutoGlyphCache glyphCache; auto& context = target->context()->internal(); - auto glyphCache = context.grContext()->contextPriv().getGlyphCache(); - auto fullAtlasManager = context.grContext()->contextPriv().getFullAtlasManager(); + auto atlasGlyphCache = context.grContext()->contextPriv().getAtlasGlyphCache(); auto resourceProvider = context.grContext()->contextPriv().resourceProvider(); + auto drawingManager = context.grContext()->contextPriv().drawingManager(); + + GrOnFlushResourceProvider onFlushResourceProvider(drawingManager); + atlasGlyphCache->preFlush(&onFlushResourceProvider, nullptr, 0, nullptr); for (int i = 0; i < fGeoCount; ++i) { GrAtlasTextBlob::VertexRegenerator regenerator( resourceProvider, fGeoData[i].fBlob, fGeoData[i].fRun, fGeoData[i].fSubRun, fGeoData[i].fViewMatrix, fGeoData[i].fX, fGeoData[i].fY, fGeoData[i].fColor, - &context, glyphCache, fullAtlasManager, &autoGlyphCache); + &context, atlasGlyphCache, &glyphCache); GrAtlasTextBlob::VertexRegenerator::Result result; do { result = regenerator.regenerate(); diff --git a/src/atlastext/SkInternalAtlasTextContext.cpp b/src/atlastext/SkInternalAtlasTextContext.cpp index 1e9cbf3079..fcb4130665 100644 --- a/src/atlastext/SkInternalAtlasTextContext.cpp +++ b/src/atlastext/SkInternalAtlasTextContext.cpp @@ -10,7 +10,7 @@ #include "GrContextPriv.h" #include "SkAtlasTextContext.h" #include "SkAtlasTextRenderer.h" -#include "text/GrGlyphCache.h" +#include "text/GrAtlasGlyphCache.h" SkAtlasTextRenderer* SkGetAtlasTextRendererFromInternalContext( class SkInternalAtlasTextContext& internal) { @@ -38,17 +38,17 @@ SkInternalAtlasTextContext::SkInternalAtlasTextContext(sk_spcontextPriv().getRestrictedAtlasManager(); + auto atlasGlyphCache = fGrContext->contextPriv().getAtlasGlyphCache(); unsigned int numProxies; - restrictedAtlasManager->getProxies(kA8_GrMaskFormat, &numProxies); + atlasGlyphCache->getProxies(kA8_GrMaskFormat, &numProxies); SkASSERT(1 == numProxies); #endif fRenderer->deleteTexture(fDistanceFieldAtlas.fTextureHandle); } } -GrGlyphCache* SkInternalAtlasTextContext::glyphCache() { - return fGrContext->contextPriv().getGlyphCache(); +GrAtlasGlyphCache* SkInternalAtlasTextContext::atlasGlyphCache() { + return fGrContext->contextPriv().getAtlasGlyphCache(); } GrTextBlobCache* SkInternalAtlasTextContext::textBlobCache() { @@ -86,11 +86,11 @@ void SkInternalAtlasTextContext::recordDraw(const void* srcVertexData, int glyph } void SkInternalAtlasTextContext::flush() { - auto* restrictedAtlasManager = fGrContext->contextPriv().getRestrictedAtlasManager(); + auto* atlasGlyphCache = fGrContext->contextPriv().getAtlasGlyphCache(); if (!fDistanceFieldAtlas.fProxy) { unsigned int numProxies; - fDistanceFieldAtlas.fProxy = restrictedAtlasManager->getProxies(kA8_GrMaskFormat, - &numProxies)->get(); + fDistanceFieldAtlas.fProxy = atlasGlyphCache->getProxies(kA8_GrMaskFormat, + &numProxies)->get(); SkASSERT(1 == numProxies); fDistanceFieldAtlas.fTextureHandle = fRenderer->createTexture(SkAtlasTextRenderer::AtlasFormat::kA8, diff --git a/src/atlastext/SkInternalAtlasTextContext.h b/src/atlastext/SkInternalAtlasTextContext.h index 22cda5ca51..cdba3ad8b0 100644 --- a/src/atlastext/SkInternalAtlasTextContext.h +++ b/src/atlastext/SkInternalAtlasTextContext.h @@ -13,8 +13,8 @@ #include "SkArenaAllocList.h" #include "SkRefCnt.h" +class GrAtlasGlyphCache; class GrContext; -class GrGlyphCache; class GrTextBlobCache; class SkAtlasTextRenderer; @@ -33,7 +33,7 @@ public: SkAtlasTextRenderer* renderer() const { return fRenderer.get(); } GrContext* grContext() const { return fGrContext.get(); } - GrGlyphCache* glyphCache(); + GrAtlasGlyphCache* atlasGlyphCache(); GrTextBlobCache* textBlobCache(); const GrTokenTracker* tokenTracker() final { return &fTokenTracker; } diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 6fbc4fe04f..38e170b7a0 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -77,7 +77,6 @@ public: GrDDLContext(GrContextThreadSafeProxy* proxy) : INHERITED(proxy) {} protected: - // DDL TODO: grab a GrRestrictedAtlasManager from the proxy private: typedef GrContext INHERITED; @@ -219,8 +218,7 @@ GrContext::GrContext(GrBackend backend) fResourceCache = nullptr; fResourceProvider = nullptr; fProxyProvider = nullptr; - fGlyphCache = nullptr; - fFullAtlasManager = nullptr; + fAtlasGlyphCache = nullptr; } GrContext::GrContext(GrContextThreadSafeProxy* proxy) @@ -230,8 +228,7 @@ GrContext::GrContext(GrContextThreadSafeProxy* proxy) fResourceCache = nullptr; fResourceProvider = nullptr; fProxyProvider = nullptr; - fGlyphCache = nullptr; - fFullAtlasManager = nullptr; + fAtlasGlyphCache = nullptr; } bool GrContext::init(const GrContextOptions& options) { @@ -296,17 +293,9 @@ bool GrContext::init(const GrContextOptions& options) { } else { allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes; } - - fGlyphCache = new GrGlyphCache; - - // DDL TODO: in DDL-mode grab a GrRestrictedAtlasManager from the thread-proxy and - // do not add an onFlushCB - fFullAtlasManager = new GrAtlasManager(fProxyProvider, fGlyphCache, - options.fGlyphCacheTextureMaximumBytes, - allowMultitexturing); - this->contextPriv().addOnFlushCallbackObject(fFullAtlasManager); - - fGlyphCache->setGlyphSizeLimit(fFullAtlasManager->getGlyphSizeLimit()); + fAtlasGlyphCache = new GrAtlasGlyphCache(fProxyProvider, options.fGlyphCacheTextureMaximumBytes, + allowMultitexturing); + this->contextPriv().addOnFlushCallbackObject(fAtlasGlyphCache); fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this, this->uniqueID(), SkToBool(fGpu))); @@ -338,8 +327,7 @@ GrContext::~GrContext() { delete fResourceProvider; delete fResourceCache; delete fProxyProvider; - delete fGlyphCache; - delete fFullAtlasManager; + delete fAtlasGlyphCache; } sk_sp GrContext::threadSafeProxy() { @@ -398,8 +386,7 @@ void GrContext::abandonContext() { fGpu->disconnect(GrGpu::DisconnectType::kAbandon); - fGlyphCache->freeAll(); - fFullAtlasManager->freeAll(); + fAtlasGlyphCache->freeAll(); fTextBlobCache->freeAll(); } @@ -418,8 +405,7 @@ void GrContext::releaseResourcesAndAbandonContext() { fGpu->disconnect(GrGpu::DisconnectType::kCleanup); - fGlyphCache->freeAll(); - fFullAtlasManager->freeAll(); + fAtlasGlyphCache->freeAll(); fTextBlobCache->freeAll(); } @@ -433,8 +419,7 @@ void GrContext::freeGpuResources() { this->flush(); - fGlyphCache->freeAll(); - fFullAtlasManager->freeAll(); + fAtlasGlyphCache->freeAll(); fDrawingManager->freeGpuResources(); diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h index c2e525d9b9..a2a45b5007 100644 --- a/src/gpu/GrContextPriv.h +++ b/src/gpu/GrContextPriv.h @@ -10,7 +10,6 @@ #include "GrContext.h" #include "GrSurfaceContext.h" -#include "text/GrAtlasManager.h" class GrBackendRenderTarget; class GrOnFlushCallbackObject; @@ -188,19 +187,8 @@ public: GrGpu* getGpu() { return fContext->fGpu.get(); } const GrGpu* getGpu() const { return fContext->fGpu.get(); } - GrGlyphCache* getGlyphCache() { return fContext->fGlyphCache; } + GrAtlasGlyphCache* getAtlasGlyphCache() { return fContext->fAtlasGlyphCache; } GrTextBlobCache* getTextBlobCache() { return fContext->fTextBlobCache.get(); } - GrRestrictedAtlasManager* getRestrictedAtlasManager() { return fContext->fFullAtlasManager; } - - // This accessor should only ever be called by the GrOpFlushState. - GrAtlasManager* getFullAtlasManager() { - if (fContext->fResourceProvider) { - // Disallow access to the full atlasManager when recording DDLs - return fContext->fFullAtlasManager; - } - - return nullptr; - } void moveOpListsToDDL(SkDeferredDisplayList*); void copyOpListsFromDDL(const SkDeferredDisplayList*, GrRenderTargetProxy* newDest); diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp index 56dfcef56d..3fd3110dcc 100644 --- a/src/gpu/GrDrawOpAtlas.cpp +++ b/src/gpu/GrDrawOpAtlas.cpp @@ -14,7 +14,6 @@ #include "GrRectanizer.h" #include "GrProxyProvider.h" #include "GrResourceProvider.h" -#include "GrSurfaceProxyPriv.h" #include "GrTexture.h" #include "GrTracing.h" @@ -337,8 +336,8 @@ bool GrDrawOpAtlas::addToAtlas(GrResourceProvider* resourceProvider, // With c+14 we could move sk_sp into lambda to only ref once. sk_sp plotsp(SkRef(newPlot.get())); + SkASSERT(fProxies[pageIdx]->priv().isInstantiated()); GrTextureProxy* proxy = fProxies[pageIdx].get(); - SkASSERT(proxy->priv().isInstantiated()); GrDeferredUploadToken lastUploadToken = target->addInlineUpload( [plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) { diff --git a/src/gpu/GrOpFlushState.cpp b/src/gpu/GrOpFlushState.cpp index 53986c5f6a..06a05c6bb3 100644 --- a/src/gpu/GrOpFlushState.cpp +++ b/src/gpu/GrOpFlushState.cpp @@ -7,7 +7,6 @@ #include "GrOpFlushState.h" -#include "GrContextPriv.h" #include "GrDrawOpAtlas.h" #include "GrGpu.h" #include "GrResourceProvider.h" @@ -192,11 +191,3 @@ void GrOpFlushState::putBackVertices(int vertices, size_t vertexStride) { GrAppliedClip GrOpFlushState::detachAppliedClip() { return fOpArgs->fAppliedClip ? std::move(*fOpArgs->fAppliedClip) : GrAppliedClip(); } - -GrGlyphCache* GrOpFlushState::glyphCache() const { - return fGpu->getContext()->contextPriv().getGlyphCache(); -} - -GrAtlasManager* GrOpFlushState::fullAtlasManager() const { - return fGpu->getContext()->contextPriv().getFullAtlasManager(); -} diff --git a/src/gpu/GrOpFlushState.h b/src/gpu/GrOpFlushState.h index ad33a98e2d..1f77c25cb7 100644 --- a/src/gpu/GrOpFlushState.h +++ b/src/gpu/GrOpFlushState.h @@ -90,12 +90,6 @@ public: const GrCaps& caps() const final; GrResourceProvider* resourceProvider() const final { return fResourceProvider; } - GrGlyphCache* glyphCache() const final; - - // At this point we know we're flushing so full access to the GrAtlasManager is required (and - // permissible). - GrAtlasManager* fullAtlasManager() const final; - private: /** GrMeshDrawOp::Target override. */ SkArenaAlloc* pipelineArena() override { return &fArena; } diff --git a/src/gpu/GrProxyProvider.h b/src/gpu/GrProxyProvider.h index 254686a613..dfd06dfe80 100644 --- a/src/gpu/GrProxyProvider.h +++ b/src/gpu/GrProxyProvider.h @@ -8,13 +8,13 @@ #ifndef GrProxyProvider_DEFINED #define GrProxyProvider_DEFINED -#include "GrCaps.h" #include "GrResourceKey.h" #include "GrTextureProxy.h" #include "GrTypes.h" #include "SkRefCnt.h" #include "SkTDynamicHash.h" +class GrCaps; class GrResourceProvider; class GrSingleOwner; class GrBackendRenderTarget; @@ -207,7 +207,6 @@ public: void processInvalidProxyUniqueKey(const GrUniqueKey&, GrTextureProxy*, bool invalidateSurface); const GrCaps* caps() const { return fCaps.get(); } - sk_sp refCaps() const { return fCaps; } void abandon() { fResourceCache = nullptr; diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp index 8f0c555295..952b3ba5ad 100644 --- a/src/gpu/ops/GrAtlasTextOp.cpp +++ b/src/gpu/ops/GrAtlasTextOp.cpp @@ -16,8 +16,7 @@ #include "SkPoint3.h" #include "effects/GrBitmapTextGeoProc.h" #include "effects/GrDistanceFieldGeoProc.h" -#include "text/GrAtlasManager.h" -#include "text/GrGlyphCache.h" +#include "text/GrAtlasGlyphCache.h" /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -54,12 +53,9 @@ void GrAtlasTextOp::init() { void GrAtlasTextOp::visitProxies(const VisitProxyFunc& func) const { fProcessors.visitProxies(func); - // We need to visit the atlasManager's proxies because, although the atlasManager explicitly - // manages their lifetimes, if they fail to allocate the draws that reference them need to - // be dropped. unsigned int numProxies; - const sk_sp* proxies = fRestrictedAtlasManager->getProxies( - this->maskFormat(), &numProxies); + const sk_sp* proxies = fFontCache->getProxies(this->maskFormat(), + &numProxies); for (unsigned int i = 0; i < numProxies; ++i) { if (proxies[i]) { func(proxies[i].get()); @@ -236,15 +232,10 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { return; } - GrAtlasManager* fullAtlasManager = target->fullAtlasManager(); - SkASSERT(fRestrictedAtlasManager == fullAtlasManager); - GrGlyphCache* glyphCache = target->glyphCache(); - GrMaskFormat maskFormat = this->maskFormat(); unsigned int atlasPageCount; - const sk_sp* proxies = fullAtlasManager->getProxies(maskFormat, - &atlasPageCount); + const sk_sp* proxies = fFontCache->getProxies(maskFormat, &atlasPageCount); if (!proxies[0]) { SkDebugf("Could not allocate backing texture for atlas\n"); return; @@ -255,7 +246,7 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { target->makePipeline(fSRGBFlags, std::move(fProcessors), target->detachAppliedClip()); SkDEBUGCODE(bool dfPerspective = false); if (this->usesDistanceFields()) { - flushInfo.fGeometryProcessor = this->setupDfProcessor(fullAtlasManager); + flushInfo.fGeometryProcessor = this->setupDfProcessor(); SkDEBUGCODE(dfPerspective = fGeoData[0].fViewMatrix.hasPerspective()); } else { flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( @@ -281,15 +272,14 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { char* currVertex = reinterpret_cast(vertices); - SkAutoGlyphCache autoGlyphCache; + SkAutoGlyphCache glyphCache; // each of these is a SubRun for (int i = 0; i < fGeoCount; i++) { const Geometry& args = fGeoData[i]; Blob* blob = args.fBlob; GrAtlasTextBlob::VertexRegenerator regenerator( resourceProvider, blob, args.fRun, args.fSubRun, args.fViewMatrix, args.fX, args.fY, - args.fColor, target->deferredUploadTarget(), glyphCache, fullAtlasManager, - &autoGlyphCache); + args.fColor, target->deferredUploadTarget(), fFontCache, &glyphCache); GrAtlasTextBlob::VertexRegenerator::Result result; do { result = regenerator.regenerate(); @@ -329,14 +319,11 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { } void GrAtlasTextOp::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const { - auto fullAtlasManager = target->fullAtlasManager(); - SkASSERT(fRestrictedAtlasManager == fullAtlasManager); - GrGeometryProcessor* gp = flushInfo->fGeometryProcessor.get(); GrMaskFormat maskFormat = this->maskFormat(); unsigned int numProxies; - const sk_sp* proxies = fullAtlasManager->getProxies(maskFormat, &numProxies); + const sk_sp* proxies = fFontCache->getProxies(maskFormat, &numProxies); if (gp->numTextureSamplers() != (int) numProxies) { // During preparation the number of atlas pages has increased. // Update the proxies used in the GP to match. @@ -440,11 +427,9 @@ bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { // TODO trying to figure out why lcd is so whack // (see comments in GrAtlasTextContext::ComputeCanonicalColor) -sk_sp GrAtlasTextOp::setupDfProcessor( - GrRestrictedAtlasManager* restrictedAtlasManager) const { +sk_sp GrAtlasTextOp::setupDfProcessor() const { unsigned int numProxies; - const sk_sp* p = restrictedAtlasManager->getProxies(this->maskFormat(), - &numProxies); + const sk_sp* p = fFontCache->getProxies(this->maskFormat(), &numProxies); bool isLCD = this->isLCD(); SkMatrix localMatrix = SkMatrix::I(); diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h index ae1c95b56e..dbdce387ec 100644 --- a/src/gpu/ops/GrAtlasTextOp.h +++ b/src/gpu/ops/GrAtlasTextOp.h @@ -11,7 +11,6 @@ #include "ops/GrMeshDrawOp.h" #include "text/GrAtlasTextContext.h" #include "text/GrDistanceFieldAdjustTable.h" -#include "text/GrGlyphCache.h" class SkAtlasTextTarget; @@ -40,12 +39,11 @@ public: GrColor fColor; }; - static std::unique_ptr MakeBitmap( - GrPaint&& paint, GrMaskFormat maskFormat, - int glyphCount, GrRestrictedAtlasManager* restrictedAtlasManager) { - std::unique_ptr op(new GrAtlasTextOp(restrictedAtlasManager, - std::move(paint))); + static std::unique_ptr MakeBitmap(GrPaint&& paint, GrMaskFormat maskFormat, + int glyphCount, GrAtlasGlyphCache* fontCache) { + std::unique_ptr op(new GrAtlasTextOp(std::move(paint))); + op->fFontCache = fontCache; switch (maskFormat) { case kA8_GrMaskFormat: op->fMaskType = kGrayscaleCoverageMask_MaskType; @@ -60,17 +58,18 @@ public: op->fNumGlyphs = glyphCount; op->fGeoCount = 1; op->fLuminanceColor = 0; + op->fFontCache = fontCache; return op; } static std::unique_ptr MakeDistanceField( - GrPaint&& paint, int glyphCount, GrRestrictedAtlasManager* restrictedAtlasManager, + GrPaint&& paint, int glyphCount, GrAtlasGlyphCache* fontCache, const GrDistanceFieldAdjustTable* distanceAdjustTable, bool useGammaCorrectDistanceTable, SkColor luminanceColor, bool isLCD, bool useBGR, bool isAntiAliased) { - std::unique_ptr op(new GrAtlasTextOp(restrictedAtlasManager, - std::move(paint))); + std::unique_ptr op(new GrAtlasTextOp(std::move(paint))); + op->fFontCache = fontCache; op->fMaskType = !isAntiAliased ? kAliasedDistanceField_MaskType : isLCD ? (useBGR ? kLCDBGRDistanceField_MaskType : kLCDDistanceField_MaskType) @@ -121,9 +120,8 @@ private: // The minimum number of Geometry we will try to allocate. static constexpr auto kMinGeometryAllocated = 12; - GrAtlasTextOp(GrRestrictedAtlasManager* restrictedAtlasManager, GrPaint&& paint) + GrAtlasTextOp(GrPaint&& paint) : INHERITED(ClassID()) - , fRestrictedAtlasManager(restrictedAtlasManager) , fGeoDataAllocSize(kMinGeometryAllocated) , fSRGBFlags(GrPipeline::SRGBFlagsFromPaint(paint)) , fProcessors(std::move(paint)) {} @@ -176,9 +174,8 @@ private: bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override; - sk_sp setupDfProcessor(GrRestrictedAtlasManager*) const; + sk_sp setupDfProcessor() const; - GrRestrictedAtlasManager* fRestrictedAtlasManager; SkAutoSTMalloc fGeoData; int fGeoDataAllocSize; uint32_t fSRGBFlags; @@ -188,6 +185,7 @@ private: int fGeoCount; int fNumGlyphs; MaskType fMaskType; + GrAtlasGlyphCache* fFontCache; // Distance field properties sk_sp fDistanceAdjustTable; SkColor fLuminanceColor; diff --git a/src/gpu/ops/GrMeshDrawOp.h b/src/gpu/ops/GrMeshDrawOp.h index 766fd23ce5..1b8831cfe8 100644 --- a/src/gpu/ops/GrMeshDrawOp.h +++ b/src/gpu/ops/GrMeshDrawOp.h @@ -15,9 +15,7 @@ #include "SkTLList.h" -class GrAtlasManager; class GrCaps; -class GrGlyphCache; class GrOpFlushState; /** @@ -154,9 +152,6 @@ public: virtual GrResourceProvider* resourceProvider() const = 0; - virtual GrGlyphCache* glyphCache() const = 0; - virtual GrAtlasManager* fullAtlasManager() const = 0; - virtual const GrCaps& caps() const = 0; virtual GrDeferredUploadTarget* deferredUploadTarget() = 0; diff --git a/src/gpu/text/GrAtlasGlyphCache.cpp b/src/gpu/text/GrAtlasGlyphCache.cpp new file mode 100644 index 0000000000..f7b1e1269a --- /dev/null +++ b/src/gpu/text/GrAtlasGlyphCache.cpp @@ -0,0 +1,489 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrAtlasGlyphCache.h" +#include "GrContext.h" +#include "GrDistanceFieldGenFromVector.h" +#include "GrGpu.h" +#include "GrProxyProvider.h" +#include "GrRectanizer.h" + +#include "SkAutoMalloc.h" +#include "SkDistanceFieldGen.h" +#include "SkMathPriv.h" +#include "SkString.h" + +bool GrAtlasGlyphCache::initAtlas(GrMaskFormat format) { + int index = MaskFormatToAtlasIndex(format); + if (!fAtlases[index]) { + GrPixelConfig config = MaskFormatToPixelConfig(format, *fProxyProvider->caps()); + int width = fAtlasConfigs[index].fWidth; + int height = fAtlasConfigs[index].fHeight; + int numPlotsX = fAtlasConfigs[index].numPlotsX(); + int numPlotsY = fAtlasConfigs[index].numPlotsY(); + + fAtlases[index] = GrDrawOpAtlas::Make(fProxyProvider, config, width, height, + numPlotsX, numPlotsY, fAllowMultitexturing, + &GrAtlasGlyphCache::HandleEviction, (void*)this); + if (!fAtlases[index]) { + return false; + } + } + return true; +} + +GrAtlasGlyphCache::GrAtlasGlyphCache(GrProxyProvider* proxyProvider, float maxTextureBytes, + GrDrawOpAtlas::AllowMultitexturing allowMultitexturing) + : fProxyProvider(proxyProvider) + , fAllowMultitexturing(allowMultitexturing) + , fPreserveStrike(nullptr) { + // Calculate RGBA size. Must be between 512 x 256 and MaxTextureSize x MaxTextureSize / 2 + int log2MaxTextureSize = SkPrevLog2(fProxyProvider->caps()->maxTextureSize()); + int log2MaxDim = 9; + for (; log2MaxDim <= log2MaxTextureSize; ++log2MaxDim) { + int maxDim = 1 << log2MaxDim; + int minDim = 1 << (log2MaxDim - 1); + + if (maxDim * minDim * 4 >= maxTextureBytes) break; + } + + int log2MinDim = log2MaxDim - 1; + int maxDim = 1 << log2MaxDim; + int minDim = 1 << log2MinDim; + // Plots are either 256 or 512. + int maxPlot = SkTMin(512, SkTMax(256, 1 << (log2MaxDim - 2))); + int minPlot = SkTMin(512, SkTMax(256, 1 << (log2MaxDim - 3))); + + // Setup default atlas configs. The A8 atlas uses maxDim for both width and height, as the A8 + // format is already very compact. + fAtlasConfigs[kA8_GrMaskFormat].fWidth = maxDim; + fAtlasConfigs[kA8_GrMaskFormat].fHeight = maxDim; + fAtlasConfigs[kA8_GrMaskFormat].fPlotWidth = maxPlot; + fAtlasConfigs[kA8_GrMaskFormat].fPlotHeight = minPlot; + + // A565 and ARGB use maxDim x minDim. + fAtlasConfigs[kA565_GrMaskFormat].fWidth = minDim; + fAtlasConfigs[kA565_GrMaskFormat].fHeight = maxDim; + fAtlasConfigs[kA565_GrMaskFormat].fPlotWidth = minPlot; + fAtlasConfigs[kA565_GrMaskFormat].fPlotHeight = minPlot; + + fAtlasConfigs[kARGB_GrMaskFormat].fWidth = minDim; + fAtlasConfigs[kARGB_GrMaskFormat].fHeight = maxDim; + fAtlasConfigs[kARGB_GrMaskFormat].fPlotWidth = minPlot; + fAtlasConfigs[kARGB_GrMaskFormat].fPlotHeight = minPlot; + + fGlyphSizeLimit = minPlot; +} + +GrAtlasGlyphCache::~GrAtlasGlyphCache() { + StrikeHash::Iter iter(&fCache); + while (!iter.done()) { + (*iter).fIsAbandoned = true; + (*iter).unref(); + ++iter; + } +} + +void GrAtlasGlyphCache::freeAll() { + StrikeHash::Iter iter(&fCache); + while (!iter.done()) { + (*iter).fIsAbandoned = true; + (*iter).unref(); + ++iter; + } + fCache.rewind(); + for (int i = 0; i < kMaskFormatCount; ++i) { + fAtlases[i] = nullptr; + } +} + +void GrAtlasGlyphCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) { + GrAtlasGlyphCache* fontCache = reinterpret_cast(ptr); + + StrikeHash::Iter iter(&fontCache->fCache); + for (; !iter.done(); ++iter) { + GrAtlasTextStrike* strike = &*iter; + strike->removeID(id); + + // clear out any empty strikes. We will preserve the strike whose call to addToAtlas + // triggered the eviction + if (strike != fontCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) { + fontCache->fCache.remove(GrAtlasTextStrike::GetKey(*strike)); + strike->fIsAbandoned = true; + strike->unref(); + } + } +} + +#ifdef SK_DEBUG +#include "GrContextPriv.h" +#include "GrSurfaceProxy.h" +#include "GrSurfaceContext.h" +#include "GrTextureProxy.h" + +#include "SkBitmap.h" +#include "SkImageEncoder.h" +#include "SkStream.h" +#include + +/** + * Write the contents of the surface proxy to a PNG. Returns true if successful. + * @param filename Full path to desired file + */ +static bool save_pixels(GrContext* context, GrSurfaceProxy* sProxy, const char* filename) { + if (!sProxy) { + return false; + } + + SkImageInfo ii = SkImageInfo::Make(sProxy->width(), sProxy->height(), + kRGBA_8888_SkColorType, kPremul_SkAlphaType); + SkBitmap bm; + if (!bm.tryAllocPixels(ii)) { + return false; + } + + sk_sp sContext(context->contextPriv().makeWrappedSurfaceContext( + sk_ref_sp(sProxy))); + if (!sContext || !sContext->asTextureProxy()) { + return false; + } + + bool result = sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), 0, 0); + if (!result) { + SkDebugf("------ failed to read pixels for %s\n", filename); + return false; + } + + // remove any previous version of this file + remove(filename); + + SkFILEWStream file(filename); + if (!file.isValid()) { + SkDebugf("------ failed to create file: %s\n", filename); + remove(filename); // remove any partial file + return false; + } + + if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) { + SkDebugf("------ failed to encode %s\n", filename); + remove(filename); // remove any partial file + return false; + } + + return true; +} + +void GrAtlasGlyphCache::dump(GrContext* context) const { + static int gDumpCount = 0; + for (int i = 0; i < kMaskFormatCount; ++i) { + if (fAtlases[i]) { + const sk_sp* proxies = fAtlases[i]->getProxies(); + for (uint32_t pageIdx = 0; pageIdx < fAtlases[i]->numActivePages(); ++pageIdx) { + SkASSERT(proxies[pageIdx]); + SkString filename; +#ifdef SK_BUILD_FOR_ANDROID + filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx); +#else + filename.printf("fontcache_%d%d%d.png", gDumpCount, i, pageIdx); +#endif + + save_pixels(context, proxies[pageIdx].get(), filename.c_str()); + } + } + } + ++gDumpCount; +} +#endif + +void GrAtlasGlyphCache::setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]) { + // Delete any old atlases. + // This should be safe to do as long as we are not in the middle of a flush. + for (int i = 0; i < kMaskFormatCount; i++) { + fAtlases[i] = nullptr; + } + memcpy(fAtlasConfigs, configs, sizeof(fAtlasConfigs)); +} + +/////////////////////////////////////////////////////////////////////////////// + +static inline GrMaskFormat get_packed_glyph_mask_format(const SkGlyph& glyph) { + SkMask::Format format = static_cast(glyph.fMaskFormat); + switch (format) { + case SkMask::kBW_Format: + // fall through to kA8 -- we store BW glyphs in our 8-bit cache + case SkMask::kA8_Format: + return kA8_GrMaskFormat; + case SkMask::k3D_Format: + return kA8_GrMaskFormat; // ignore the mul and add planes, just use the mask + case SkMask::kLCD16_Format: + return kA565_GrMaskFormat; + case SkMask::kARGB32_Format: + return kARGB_GrMaskFormat; + default: + SkDEBUGFAIL("unsupported SkMask::Format"); + return kA8_GrMaskFormat; + } +} + +static inline bool get_packed_glyph_bounds(SkGlyphCache* cache, const SkGlyph& glyph, + SkIRect* bounds) { +#if 1 + // crbug:510931 + // Retrieving the image from the cache can actually change the mask format. + cache->findImage(glyph); +#endif + bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight); + + return true; +} + +static inline bool get_packed_glyph_df_bounds(SkGlyphCache* cache, const SkGlyph& glyph, + SkIRect* bounds) { +#if 1 + // crbug:510931 + // Retrieving the image from the cache can actually change the mask format. + cache->findImage(glyph); +#endif + bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight); + bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad); + + return true; +} + +// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to +// A8, RGB565, or RGBA8888. +template +static void expand_bits(INT_TYPE* dst, + const uint8_t* src, + int width, + int height, + int dstRowBytes, + int srcRowBytes) { + for (int i = 0; i < height; ++i) { + int rowWritesLeft = width; + const uint8_t* s = src; + INT_TYPE* d = dst; + while (rowWritesLeft > 0) { + unsigned mask = *s++; + for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) { + *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0; + } + } + dst = reinterpret_cast(reinterpret_cast(dst) + dstRowBytes); + src += srcRowBytes; + } +} + +static bool get_packed_glyph_image(SkGlyphCache* cache, const SkGlyph& glyph, int width, + int height, int dstRB, GrMaskFormat expectedMaskFormat, + void* dst) { + SkASSERT(glyph.fWidth == width); + SkASSERT(glyph.fHeight == height); + const void* src = cache->findImage(glyph); + if (nullptr == src) { + return false; + } + + // crbug:510931 + // Retrieving the image from the cache can actually change the mask format. This case is very + // uncommon so for now we just draw a clear box for these glyphs. + if (get_packed_glyph_mask_format(glyph) != expectedMaskFormat) { + const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat); + for (int y = 0; y < height; y++) { + sk_bzero(dst, width * bpp); + dst = (char*)dst + dstRB; + } + return true; + } + + int srcRB = glyph.rowBytes(); + // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to + // check the glyph's format, not the strike's format, and to be able to convert to any of the + // GrMaskFormats. + if (SkMask::kBW_Format == glyph.fMaskFormat) { + // expand bits to our mask type + const uint8_t* bits = reinterpret_cast(src); + switch (expectedMaskFormat) { + case kA8_GrMaskFormat:{ + uint8_t* bytes = reinterpret_cast(dst); + expand_bits(bytes, bits, width, height, dstRB, srcRB); + break; + } + case kA565_GrMaskFormat: { + uint16_t* rgb565 = reinterpret_cast(dst); + expand_bits(rgb565, bits, width, height, dstRB, srcRB); + break; + } + default: + SK_ABORT("Invalid GrMaskFormat"); + } + } else if (srcRB == dstRB) { + memcpy(dst, src, dstRB * height); + } else { + const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat); + for (int y = 0; y < height; y++) { + memcpy(dst, src, width * bbp); + src = (const char*)src + srcRB; + dst = (char*)dst + dstRB; + } + } + return true; +} + +static bool get_packed_glyph_df_image(SkGlyphCache* cache, const SkGlyph& glyph, + int width, int height, void* dst) { + SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width); + SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height); + +#ifndef SK_USE_LEGACY_DISTANCE_FIELDS + const SkPath* path = cache->findPath(glyph); + if (nullptr == path) { + return false; + } + + SkDEBUGCODE(SkRect glyphBounds = SkRect::MakeXYWH(glyph.fLeft, + glyph.fTop, + glyph.fWidth, + glyph.fHeight)); + SkASSERT(glyphBounds.contains(path->getBounds())); + + // now generate the distance field + SkASSERT(dst); + SkMatrix drawMatrix; + drawMatrix.setTranslate((SkScalar)-glyph.fLeft, (SkScalar)-glyph.fTop); + + // Generate signed distance field directly from SkPath + bool succeed = GrGenerateDistanceFieldFromPath((unsigned char*)dst, + *path, drawMatrix, + width, height, width * sizeof(unsigned char)); + + if (!succeed) { +#endif + const void* image = cache->findImage(glyph); + if (nullptr == image) { + return false; + } + + // now generate the distance field + SkASSERT(dst); + SkMask::Format maskFormat = static_cast(glyph.fMaskFormat); + if (SkMask::kA8_Format == maskFormat) { + // make the distance field from the image + SkGenerateDistanceFieldFromA8Image((unsigned char*)dst, + (unsigned char*)image, + glyph.fWidth, glyph.fHeight, + glyph.rowBytes()); + } else if (SkMask::kBW_Format == maskFormat) { + // make the distance field from the image + SkGenerateDistanceFieldFromBWImage((unsigned char*)dst, + (unsigned char*)image, + glyph.fWidth, glyph.fHeight, + glyph.rowBytes()); + } else { + return false; + } +#ifndef SK_USE_LEGACY_DISTANCE_FIELDS + } +#endif + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +/* + The text strike is specific to a given font/style/matrix setup, which is + represented by the GrHostFontScaler object we are given in getGlyph(). + + We map a 32bit glyphID to a GrGlyph record, which in turn points to a + atlas and a position within that texture. + */ + +GrAtlasTextStrike::GrAtlasTextStrike(const SkDescriptor& key) + : fFontScalerKey(key) + , fPool(9/*start allocations at 512 bytes*/) + , fAtlasedGlyphs(0) + , fIsAbandoned(false) {} + +GrAtlasTextStrike::~GrAtlasTextStrike() { + SkTDynamicHash::Iter iter(&fCache); + while (!iter.done()) { + (*iter).reset(); + ++iter; + } +} + +GrGlyph* GrAtlasTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed, + SkGlyphCache* cache) { + SkIRect bounds; + if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(packed)) { + if (!get_packed_glyph_df_bounds(cache, skGlyph, &bounds)) { + return nullptr; + } + } else { + if (!get_packed_glyph_bounds(cache, skGlyph, &bounds)) { + return nullptr; + } + } + GrMaskFormat format = get_packed_glyph_mask_format(skGlyph); + + GrGlyph* glyph = fPool.make(); + glyph->init(packed, bounds, format); + fCache.add(glyph); + return glyph; +} + +void GrAtlasTextStrike::removeID(GrDrawOpAtlas::AtlasID id) { + SkTDynamicHash::Iter iter(&fCache); + while (!iter.done()) { + if (id == (*iter).fID) { + (*iter).fID = GrDrawOpAtlas::kInvalidAtlasID; + fAtlasedGlyphs--; + SkASSERT(fAtlasedGlyphs >= 0); + } + ++iter; + } +} + +bool GrAtlasTextStrike::addGlyphToAtlas(GrResourceProvider* resourceProvider, + GrDeferredUploadTarget* target, + GrAtlasGlyphCache* atlasGlyphCache, + GrGlyph* glyph, + SkGlyphCache* cache, + GrMaskFormat expectedMaskFormat) { + SkASSERT(glyph); + SkASSERT(cache); + SkASSERT(fCache.find(glyph->fPackedID)); + + int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat); + + size_t size = glyph->fBounds.area() * bytesPerPixel; + SkAutoSMalloc<1024> storage(size); + + const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID); + if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) { + if (!get_packed_glyph_df_image(cache, skGlyph, glyph->width(), glyph->height(), + storage.get())) { + return false; + } + } else { + if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(), + glyph->width() * bytesPerPixel, expectedMaskFormat, + storage.get())) { + return false; + } + } + + bool success = atlasGlyphCache->addToAtlas(resourceProvider, this, &glyph->fID, target, + expectedMaskFormat, + glyph->width(), glyph->height(), + storage.get(), &glyph->fAtlasLocation); + if (success) { + SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID); + fAtlasedGlyphs++; + } + return success; +} diff --git a/src/gpu/text/GrAtlasGlyphCache.h b/src/gpu/text/GrAtlasGlyphCache.h new file mode 100644 index 0000000000..84b7d1b249 --- /dev/null +++ b/src/gpu/text/GrAtlasGlyphCache.h @@ -0,0 +1,270 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrAtlasGlyphCache_DEFINED +#define GrAtlasGlyphCache_DEFINED + +#include "GrCaps.h" +#include "GrDrawOpAtlas.h" +#include "GrGlyph.h" +#include "GrOnFlushResourceProvider.h" +#include "SkArenaAlloc.h" +#include "SkGlyphCache.h" +#include "SkTDynamicHash.h" + +class GrAtlasGlyphCache; +class GrGpu; + +/** + * The GrAtlasTextStrike manages a pool of CPU backing memory for GrGlyphs. This backing memory + * is indexed by a PackedID and SkGlyphCache. The SkGlyphCache is what actually creates the mask. + * The GrAtlasTextStrike may outlive the generating SkGlyphCache. However, it retains a copy + * of it's SkDescriptor as a key to access (or regenerate) the SkGlyphCache. GrAtlasTextStrike are + * created by and owned by a GrAtlasGlyphCache. + */ +class GrAtlasTextStrike : public SkNVRefCnt { +public: + GrAtlasTextStrike(const SkDescriptor& fontScalerKey); + ~GrAtlasTextStrike(); + + inline GrGlyph* getGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed, + SkGlyphCache* cache) { + GrGlyph* glyph = fCache.find(packed); + if (nullptr == glyph) { + glyph = this->generateGlyph(skGlyph, packed, cache); + } + return glyph; + } + + // This variant of the above function is called by GrAtlasTextOp. At this point, it is possible + // that the maskformat of the glyph differs from what we expect. In these cases we will just + // draw a clear square. + // skbug:4143 crbug:510931 + inline GrGlyph* getGlyph(GrGlyph::PackedID packed, + GrMaskFormat expectedMaskFormat, + SkGlyphCache* cache) { + GrGlyph* glyph = fCache.find(packed); + if (nullptr == glyph) { + // We could return this to the caller, but in practice it adds code complexity for + // potentially little benefit(ie, if the glyph is not in our font cache, then its not + // in the atlas and we're going to be doing a texture upload anyways). + const SkGlyph& skGlyph = GrToSkGlyph(cache, packed); + glyph = this->generateGlyph(skGlyph, packed, cache); + glyph->fMaskFormat = expectedMaskFormat; + } + return glyph; + } + + // returns true if glyph successfully added to texture atlas, false otherwise. If the glyph's + // mask format has changed, then addGlyphToAtlas will draw a clear box. This will almost never + // happen. + // TODO we can handle some of these cases if we really want to, but the long term solution is to + // get the actual glyph image itself when we get the glyph metrics. + bool addGlyphToAtlas(GrResourceProvider*, GrDeferredUploadTarget*, GrAtlasGlyphCache*, GrGlyph*, + SkGlyphCache*, GrMaskFormat expectedMaskFormat); + + // testing + int countGlyphs() const { return fCache.count(); } + + // remove any references to this plot + void removeID(GrDrawOpAtlas::AtlasID); + + // If a TextStrike is abandoned by the cache, then the caller must get a new strike + bool isAbandoned() const { return fIsAbandoned; } + + static const SkDescriptor& GetKey(const GrAtlasTextStrike& ts) { + return *ts.fFontScalerKey.getDesc(); + } + + static uint32_t Hash(const SkDescriptor& desc) { return desc.getChecksum(); } + +private: + SkTDynamicHash fCache; + SkAutoDescriptor fFontScalerKey; + SkArenaAlloc fPool{512}; + + int fAtlasedGlyphs; + bool fIsAbandoned; + + static const SkGlyph& GrToSkGlyph(SkGlyphCache* cache, GrGlyph::PackedID id) { + return cache->getGlyphIDMetrics(GrGlyph::UnpackID(id), + GrGlyph::UnpackFixedX(id), + GrGlyph::UnpackFixedY(id)); + } + + GrGlyph* generateGlyph(const SkGlyph&, GrGlyph::PackedID, SkGlyphCache*); + + friend class GrAtlasGlyphCache; +}; + +/** + * GrAtlasGlyphCache manages strikes which are indexed by a SkGlyphCache. These strikes can then be + * used to generate individual Glyph Masks. The GrAtlasGlyphCache also manages GrDrawOpAtlases, + * though this is more or less transparent to the client(aside from atlasGeneration, described + * below). + */ +class GrAtlasGlyphCache : public GrOnFlushCallbackObject { +public: + GrAtlasGlyphCache(GrProxyProvider*, float maxTextureBytes, + GrDrawOpAtlas::AllowMultitexturing); + ~GrAtlasGlyphCache() override; + // The user of the cache may hold a long-lived ref to the returned strike. However, actions by + // another client of the cache may cause the strike to be purged while it is still reffed. + // Therefore, the caller must check GrAtlasTextStrike::isAbandoned() if there are other + // interactions with the cache since the strike was received. + inline GrAtlasTextStrike* getStrike(const SkGlyphCache* cache) { + GrAtlasTextStrike* strike = fCache.find(cache->getDescriptor()); + if (nullptr == strike) { + strike = this->generateStrike(cache); + } + return strike; + } + + void freeAll(); + + // if getProxies returns nullptr, the client must not try to use other functions on the + // GrAtlasGlyphCache which use the atlas. This function *must* be called first, before other + // functions which use the atlas. + const sk_sp* getProxies(GrMaskFormat format, unsigned int* numProxies) { + SkASSERT(numProxies); + + if (this->initAtlas(format)) { + *numProxies = this->getAtlas(format)->numActivePages(); + return this->getAtlas(format)->getProxies(); + } + *numProxies = 0; + return nullptr; + } + + SkScalar getGlyphSizeLimit() const { return fGlyphSizeLimit; } + + bool hasGlyph(GrGlyph* glyph) { + SkASSERT(glyph); + return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID); + } + + // To ensure the GrDrawOpAtlas does not evict the Glyph Mask from its texture backing store, + // the client must pass in the current op token along with the GrGlyph. + // A BulkUseTokenUpdater is used to manage bulk last use token updating in the Atlas. + // For convenience, this function will also set the use token for the current glyph if required + // NOTE: the bulk uploader is only valid if the subrun has a valid atlasGeneration + void addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater* updater, GrGlyph* glyph, + GrDeferredUploadToken token) { + SkASSERT(glyph); + updater->add(glyph->fID); + this->getAtlas(glyph->fMaskFormat)->setLastUseToken(glyph->fID, token); + } + + void setUseTokenBulk(const GrDrawOpAtlas::BulkUseTokenUpdater& updater, + GrDeferredUploadToken token, + GrMaskFormat format) { + this->getAtlas(format)->setLastUseTokenBulk(updater, token); + } + + // add to texture atlas that matches this format + bool addToAtlas(GrResourceProvider* resourceProvider, GrAtlasTextStrike* strike, + GrDrawOpAtlas::AtlasID* id, + GrDeferredUploadTarget* target, GrMaskFormat format, int width, int height, + const void* image, SkIPoint16* loc) { + fPreserveStrike = strike; + return this->getAtlas(format)->addToAtlas(resourceProvider, id, target, + width, height, image, loc); + } + + // Some clients may wish to verify the integrity of the texture backing store of the + // GrDrawOpAtlas. The atlasGeneration returned below is a monotonically increasing number which + // changes every time something is removed from the texture backing store. + uint64_t atlasGeneration(GrMaskFormat format) const { + return this->getAtlas(format)->atlasGeneration(); + } + + // GrOnFlushCallbackObject overrides + + void preFlush(GrOnFlushResourceProvider* onFlushResourceProvider, const uint32_t*, int, + SkTArray>*) override { + for (int i = 0; i < kMaskFormatCount; ++i) { + if (fAtlases[i]) { + fAtlases[i]->instantiate(onFlushResourceProvider); + } + } + } + + void postFlush(GrDeferredUploadToken startTokenForNextFlush, const uint32_t*, int) override { + for (int i = 0; i < kMaskFormatCount; ++i) { + if (fAtlases[i]) { + fAtlases[i]->compact(startTokenForNextFlush); + } + } + } + + // The AtlasGlyph cache always survives freeGpuResources so we want it to remain in the active + // OnFlushCallbackObject list + bool retainOnFreeGpuResources() override { return true; } + + /////////////////////////////////////////////////////////////////////////// + // Functions intended debug only +#ifdef SK_DEBUG + void dump(GrContext*) const; +#endif + + void setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]); + +private: + static GrPixelConfig MaskFormatToPixelConfig(GrMaskFormat format, const GrCaps& caps) { + switch (format) { + case kA8_GrMaskFormat: + return kAlpha_8_GrPixelConfig; + case kA565_GrMaskFormat: + return kRGB_565_GrPixelConfig; + case kARGB_GrMaskFormat: + return caps.srgbSupport() ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig; + default: + SkDEBUGFAIL("unsupported GrMaskFormat"); + return kAlpha_8_GrPixelConfig; + } + } + + // There is a 1:1 mapping between GrMaskFormats and atlas indices + static int MaskFormatToAtlasIndex(GrMaskFormat format) { + static const int sAtlasIndices[] = { + kA8_GrMaskFormat, + kA565_GrMaskFormat, + kARGB_GrMaskFormat, + }; + static_assert(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, "array_size_mismatch"); + + SkASSERT(sAtlasIndices[format] < kMaskFormatCount); + return sAtlasIndices[format]; + } + + bool initAtlas(GrMaskFormat); + + GrAtlasTextStrike* generateStrike(const SkGlyphCache* cache) { + GrAtlasTextStrike* strike = new GrAtlasTextStrike(cache->getDescriptor()); + fCache.add(strike); + return strike; + } + + GrDrawOpAtlas* getAtlas(GrMaskFormat format) const { + int atlasIndex = MaskFormatToAtlasIndex(format); + SkASSERT(fAtlases[atlasIndex]); + return fAtlases[atlasIndex].get(); + } + + static void HandleEviction(GrDrawOpAtlas::AtlasID, void*); + + using StrikeHash = SkTDynamicHash; + GrProxyProvider* fProxyProvider; + StrikeHash fCache; + GrDrawOpAtlas::AllowMultitexturing fAllowMultitexturing; + std::unique_ptr fAtlases[kMaskFormatCount]; + GrAtlasTextStrike* fPreserveStrike; + GrDrawOpAtlasConfig fAtlasConfigs[kMaskFormatCount]; + SkScalar fGlyphSizeLimit; +}; + +#endif diff --git a/src/gpu/text/GrAtlasManager.cpp b/src/gpu/text/GrAtlasManager.cpp deleted file mode 100644 index 6e227a94a2..0000000000 --- a/src/gpu/text/GrAtlasManager.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrAtlasManager.h" - -#include "GrCaps.h" -#include "GrGlyph.h" -#include "GrGlyphCache.h" -#include "GrProxyProvider.h" - -GrRestrictedAtlasManager::GrRestrictedAtlasManager( - sk_sp caps, - float maxTextureBytes, - GrDrawOpAtlas::AllowMultitexturing allowMultitexturing) - : fCaps(std::move(caps)) - , fAllowMultitexturing(allowMultitexturing) { - // Calculate RGBA size. Must be between 512 x 256 and MaxTextureSize x MaxTextureSize / 2 - int log2MaxTextureSize = SkPrevLog2(fCaps->maxTextureSize()); - int log2MaxDim = 9; - for (; log2MaxDim <= log2MaxTextureSize; ++log2MaxDim) { - int maxDim = 1 << log2MaxDim; - int minDim = 1 << (log2MaxDim - 1); - - if (maxDim * minDim * 4 >= maxTextureBytes) break; - } - - int log2MinDim = log2MaxDim - 1; - int maxDim = 1 << log2MaxDim; - int minDim = 1 << log2MinDim; - // Plots are either 256 or 512. - int maxPlot = SkTMin(512, SkTMax(256, 1 << (log2MaxDim - 2))); - int minPlot = SkTMin(512, SkTMax(256, 1 << (log2MaxDim - 3))); - - // Setup default atlas configs. The A8 atlas uses maxDim for both width and height, as the A8 - // format is already very compact. - fAtlasConfigs[kA8_GrMaskFormat].fWidth = maxDim; - fAtlasConfigs[kA8_GrMaskFormat].fHeight = maxDim; - fAtlasConfigs[kA8_GrMaskFormat].fPlotWidth = maxPlot; - fAtlasConfigs[kA8_GrMaskFormat].fPlotHeight = minPlot; - - // A565 and ARGB use maxDim x minDim. - fAtlasConfigs[kA565_GrMaskFormat].fWidth = minDim; - fAtlasConfigs[kA565_GrMaskFormat].fHeight = maxDim; - fAtlasConfigs[kA565_GrMaskFormat].fPlotWidth = minPlot; - fAtlasConfigs[kA565_GrMaskFormat].fPlotHeight = minPlot; - - fAtlasConfigs[kARGB_GrMaskFormat].fWidth = minDim; - fAtlasConfigs[kARGB_GrMaskFormat].fHeight = maxDim; - fAtlasConfigs[kARGB_GrMaskFormat].fPlotWidth = minPlot; - fAtlasConfigs[kARGB_GrMaskFormat].fPlotHeight = minPlot; - - fGlyphSizeLimit = minPlot; -} - -GrRestrictedAtlasManager::~GrRestrictedAtlasManager() { -} - -static GrPixelConfig mask_format_to_pixel_config(GrMaskFormat format, const GrCaps& caps) { - switch (format) { - case kA8_GrMaskFormat: - return kAlpha_8_GrPixelConfig; - case kA565_GrMaskFormat: - return kRGB_565_GrPixelConfig; - case kARGB_GrMaskFormat: - return caps.srgbSupport() ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig; - default: - SkDEBUGFAIL("unsupported GrMaskFormat"); - return kAlpha_8_GrPixelConfig; - } -} - -////////////////////////////////////////////////////////////////////////////////////////////////// -GrAtlasManager::GrAtlasManager(GrProxyProvider* proxyProvider, GrGlyphCache* glyphCache, - float maxTextureBytes, - GrDrawOpAtlas::AllowMultitexturing allowMultitexturing) - : INHERITED(proxyProvider->refCaps(), maxTextureBytes, allowMultitexturing) - , fProxyProvider(proxyProvider) - , fGlyphCache(glyphCache) { -} - -void GrAtlasManager::freeAll() { - for (int i = 0; i < kMaskFormatCount; ++i) { - fAtlases[i] = nullptr; - } -} - -bool GrAtlasManager::hasGlyph(GrGlyph* glyph) { - SkASSERT(glyph); - return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID); -} - -// add to texture atlas that matches this format -bool GrAtlasManager::addToAtlas(GrResourceProvider* resourceProvider, - GrGlyphCache* glyphCache, - GrAtlasTextStrike* strike, GrDrawOpAtlas::AtlasID* id, - GrDeferredUploadTarget* target, GrMaskFormat format, - int width, int height, const void* image, SkIPoint16* loc) { - glyphCache->setStrikeToPreserve(strike); - return this->getAtlas(format)->addToAtlas(resourceProvider, id, target, width, height, - image, loc); -} - -void GrAtlasManager::addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater* updater, - GrGlyph* glyph, - GrDeferredUploadToken token) { - SkASSERT(glyph); - updater->add(glyph->fID); - this->getAtlas(glyph->fMaskFormat)->setLastUseToken(glyph->fID, token); -} - -#ifdef SK_DEBUG -#include "GrContextPriv.h" -#include "GrSurfaceProxy.h" -#include "GrSurfaceContext.h" -#include "GrTextureProxy.h" - -#include "SkBitmap.h" -#include "SkImageEncoder.h" -#include "SkStream.h" -#include - -/** - * Write the contents of the surface proxy to a PNG. Returns true if successful. - * @param filename Full path to desired file - */ -static bool save_pixels(GrContext* context, GrSurfaceProxy* sProxy, const char* filename) { - if (!sProxy) { - return false; - } - - SkImageInfo ii = SkImageInfo::Make(sProxy->width(), sProxy->height(), - kRGBA_8888_SkColorType, kPremul_SkAlphaType); - SkBitmap bm; - if (!bm.tryAllocPixels(ii)) { - return false; - } - - sk_sp sContext(context->contextPriv().makeWrappedSurfaceContext( - sk_ref_sp(sProxy))); - if (!sContext || !sContext->asTextureProxy()) { - return false; - } - - bool result = sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), 0, 0); - if (!result) { - SkDebugf("------ failed to read pixels for %s\n", filename); - return false; - } - - // remove any previous version of this file - remove(filename); - - SkFILEWStream file(filename); - if (!file.isValid()) { - SkDebugf("------ failed to create file: %s\n", filename); - remove(filename); // remove any partial file - return false; - } - - if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) { - SkDebugf("------ failed to encode %s\n", filename); - remove(filename); // remove any partial file - return false; - } - - return true; -} - -void GrAtlasManager::dump(GrContext* context) const { - static int gDumpCount = 0; - for (int i = 0; i < kMaskFormatCount; ++i) { - if (fAtlases[i]) { - const sk_sp* proxies = fAtlases[i]->getProxies(); - for (uint32_t pageIdx = 0; pageIdx < fAtlases[i]->numActivePages(); ++pageIdx) { - SkASSERT(proxies[pageIdx]); - SkString filename; -#ifdef SK_BUILD_FOR_ANDROID - filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx); -#else - filename.printf("fontcache_%d%d%d.png", gDumpCount, i, pageIdx); -#endif - - save_pixels(context, proxies[pageIdx].get(), filename.c_str()); - } - } - } - ++gDumpCount; -} -#endif - -void GrAtlasManager::setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]) { - // Delete any old atlases. - // This should be safe to do as long as we are not in the middle of a flush. - for (int i = 0; i < kMaskFormatCount; i++) { - fAtlases[i] = nullptr; - } - memcpy(fAtlasConfigs, configs, sizeof(fAtlasConfigs)); -} - -bool GrAtlasManager::initAtlas(GrMaskFormat format) { - int index = MaskFormatToAtlasIndex(format); - if (!fAtlases[index]) { - GrPixelConfig config = mask_format_to_pixel_config(format, *fCaps); - int width = fAtlasConfigs[index].fWidth; - int height = fAtlasConfigs[index].fHeight; - int numPlotsX = fAtlasConfigs[index].numPlotsX(); - int numPlotsY = fAtlasConfigs[index].numPlotsY(); - - fAtlases[index] = GrDrawOpAtlas::Make(fProxyProvider, config, width, height, - numPlotsX, numPlotsY, fAllowMultitexturing, - &GrGlyphCache::HandleEviction, - fGlyphCache); - if (!fAtlases[index]) { - return false; - } - } - return true; -} diff --git a/src/gpu/text/GrAtlasManager.h b/src/gpu/text/GrAtlasManager.h deleted file mode 100644 index 4629cb173b..0000000000 --- a/src/gpu/text/GrAtlasManager.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrAtlasManager_DEFINED -#define GrAtlasManager_DEFINED - -#include "GrDrawOpAtlas.h" -#include "GrOnFlushResourceProvider.h" - -class GrAtlasGlypCache; -class GrAtlasTextStrike; -struct GrGlyph; - - /** The GrAtlasManager classes manage the lifetime of and access to GrDrawOpAtlases. - * The restricted version is available at op creation time and only allows basic access - * to the proxies (so the created ops can reference them). The full GrAtlasManager class - * is only available at flush time and only via the GrOpFlushState. - * - * This organization implies that all of the advanced atlasManager functionality (i.e., - * adding glyphs to the atlas) are only available at flush time. - */ -class GrRestrictedAtlasManager : public GrOnFlushCallbackObject { -public: - GrRestrictedAtlasManager(sk_sp, float maxTextureBytes, - GrDrawOpAtlas::AllowMultitexturing); - ~GrRestrictedAtlasManager() override; - - // if getProxies returns nullptr, the client must not try to use other functions on the - // GrGlyphCache which use the atlas. This function *must* be called first, before other - // functions which use the atlas. - const sk_sp* getProxies(GrMaskFormat format, unsigned int* numProxies) { - if (this->initAtlas(format)) { - *numProxies = this->getAtlas(format)->numActivePages(); - return this->getAtlas(format)->getProxies(); - } - *numProxies = 0; - return nullptr; - } - - SkScalar getGlyphSizeLimit() const { return fGlyphSizeLimit; } - -protected: - // There is a 1:1 mapping between GrMaskFormats and atlas indices - static int MaskFormatToAtlasIndex(GrMaskFormat format) { - static const int sAtlasIndices[] = { - kA8_GrMaskFormat, - kA565_GrMaskFormat, - kARGB_GrMaskFormat, - }; - static_assert(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, "array_size_mismatch"); - - SkASSERT(sAtlasIndices[format] < kMaskFormatCount); - return sAtlasIndices[format]; - } - - GrDrawOpAtlas* getAtlas(GrMaskFormat format) const { - int atlasIndex = MaskFormatToAtlasIndex(format); - SkASSERT(fAtlases[atlasIndex]); - return fAtlases[atlasIndex].get(); - } - - sk_sp fCaps; - GrDrawOpAtlas::AllowMultitexturing fAllowMultitexturing; - std::unique_ptr fAtlases[kMaskFormatCount]; - GrDrawOpAtlasConfig fAtlasConfigs[kMaskFormatCount]; - SkScalar fGlyphSizeLimit; - -private: - virtual bool initAtlas(GrMaskFormat) = 0; - - typedef GrOnFlushCallbackObject INHERITED; -}; - -////////////////////////////////////////////////////////////////////////////////////////////////// -class GrAtlasManager : public GrRestrictedAtlasManager { -public: - GrAtlasManager(GrProxyProvider*, GrGlyphCache*, - float maxTextureBytes, GrDrawOpAtlas::AllowMultitexturing); - - void freeAll(); - - bool hasGlyph(GrGlyph* glyph); - - // To ensure the GrDrawOpAtlas does not evict the Glyph Mask from its texture backing store, - // the client must pass in the current op token along with the GrGlyph. - // A BulkUseTokenUpdater is used to manage bulk last use token updating in the Atlas. - // For convenience, this function will also set the use token for the current glyph if required - // NOTE: the bulk uploader is only valid if the subrun has a valid atlasGeneration - void addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater*, GrGlyph*, - GrDeferredUploadToken); - - void setUseTokenBulk(const GrDrawOpAtlas::BulkUseTokenUpdater& updater, - GrDeferredUploadToken token, - GrMaskFormat format) { - this->getAtlas(format)->setLastUseTokenBulk(updater, token); - } - - // add to texture atlas that matches this format - bool addToAtlas(GrResourceProvider*, GrGlyphCache*, GrAtlasTextStrike*, - GrDrawOpAtlas::AtlasID*, GrDeferredUploadTarget*, GrMaskFormat, - int width, int height, const void* image, SkIPoint16* loc); - - // Some clients may wish to verify the integrity of the texture backing store of the - // GrDrawOpAtlas. The atlasGeneration returned below is a monotonically increasing number which - // changes every time something is removed from the texture backing store. - uint64_t atlasGeneration(GrMaskFormat format) const { - return this->getAtlas(format)->atlasGeneration(); - } - - // GrOnFlushCallbackObject overrides - - void preFlush(GrOnFlushResourceProvider* onFlushResourceProvider, const uint32_t*, int, - SkTArray>*) override { - for (int i = 0; i < kMaskFormatCount; ++i) { - if (fAtlases[i]) { - fAtlases[i]->instantiate(onFlushResourceProvider); - } - } - } - - void postFlush(GrDeferredUploadToken startTokenForNextFlush, - const uint32_t* opListIDs, int numOpListIDs) override { - for (int i = 0; i < kMaskFormatCount; ++i) { - if (fAtlases[i]) { - fAtlases[i]->compact(startTokenForNextFlush); - } - } - } - - // The AtlasGlyph cache always survives freeGpuResources so we want it to remain in the active - // OnFlushCallbackObject list - bool retainOnFreeGpuResources() override { return true; } - - /////////////////////////////////////////////////////////////////////////// - // Functions intended debug only -#ifdef SK_DEBUG - void dump(GrContext* context) const; -#endif - - void setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]); - -private: - bool initAtlas(GrMaskFormat) override; - - GrProxyProvider* fProxyProvider; - GrGlyphCache* fGlyphCache; - - typedef GrRestrictedAtlasManager INHERITED; -}; - -#endif // GrAtlasManager_DEFINED diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp index 35e783019f..90bcf5a224 100644 --- a/src/gpu/text/GrAtlasTextBlob.cpp +++ b/src/gpu/text/GrAtlasTextBlob.cpp @@ -250,8 +250,8 @@ inline std::unique_ptr GrAtlasTextBlob::makeOp( const Run::SubRunInfo& info, int glyphCount, uint16_t run, uint16_t subRun, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect, const GrTextUtils::Paint& paint, const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - GrRestrictedAtlasManager* restrictedAtlasManager, GrTextUtils::Target* target) { + const GrDistanceFieldAdjustTable* distanceAdjustTable, GrAtlasGlyphCache* cache, + GrTextUtils::Target* target) { GrMaskFormat format = info.maskFormat(); GrPaint grPaint; @@ -260,12 +260,11 @@ inline std::unique_ptr GrAtlasTextBlob::makeOp( if (info.drawAsDistanceFields()) { bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry()); op = GrAtlasTextOp::MakeDistanceField( - std::move(grPaint), glyphCount, restrictedAtlasManager, distanceAdjustTable, + std::move(grPaint), glyphCount, cache, distanceAdjustTable, target->colorSpaceInfo().isGammaCorrect(), paint.luminanceColor(), info.hasUseLCDText(), useBGR, info.isAntiAliased()); } else { - op = GrAtlasTextOp::MakeBitmap(std::move(grPaint), format, - glyphCount, restrictedAtlasManager); + op = GrAtlasTextOp::MakeBitmap(std::move(grPaint), format, glyphCount, cache); } GrAtlasTextOp::Geometry& geometry = op->geometry(); geometry.fViewMatrix = viewMatrix; @@ -301,8 +300,8 @@ static void calculate_translation(bool applyVM, } } -void GrAtlasTextBlob::flush(GrRestrictedAtlasManager* restrictedAtlasManager, - GrTextUtils::Target* target, const SkSurfaceProps& props, +void GrAtlasTextBlob::flush(GrAtlasGlyphCache* atlasGlyphCache, GrTextUtils::Target* target, + const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, const GrTextUtils::Paint& paint, const GrClip& clip, const SkMatrix& viewMatrix, const SkIRect& clipBounds, @@ -377,7 +376,7 @@ void GrAtlasTextBlob::flush(GrRestrictedAtlasManager* restrictedAtlasManager, if (submitOp) { auto op = this->makeOp(info, glyphCount, runIndex, subRun, viewMatrix, x, y, clipRect, std::move(paint), props, distanceAdjustTable, - restrictedAtlasManager, target); + atlasGlyphCache, target); if (op) { if (skipClip) { target->addDrawOp(GrNoClip(), std::move(op)); @@ -395,12 +394,12 @@ void GrAtlasTextBlob::flush(GrRestrictedAtlasManager* restrictedAtlasManager, std::unique_ptr GrAtlasTextBlob::test_makeOp( int glyphCount, uint16_t run, uint16_t subRun, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const GrTextUtils::Paint& paint, const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - GrRestrictedAtlasManager* restrictedAtlasManager, GrTextUtils::Target* target) { + const GrDistanceFieldAdjustTable* distanceAdjustTable, GrAtlasGlyphCache* cache, + GrTextUtils::Target* target) { const GrAtlasTextBlob::Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun]; SkIRect emptyRect = SkIRect::MakeEmpty(); return this->makeOp(info, glyphCount, run, subRun, viewMatrix, x, y, emptyRect, paint, props, - distanceAdjustTable, restrictedAtlasManager, target); + distanceAdjustTable, cache, target); } void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlob& r) { diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h index 9f91cae957..0fae3cd8c7 100644 --- a/src/gpu/text/GrAtlasTextBlob.h +++ b/src/gpu/text/GrAtlasTextBlob.h @@ -8,9 +8,9 @@ #ifndef GrAtlasTextBlob_DEFINED #define GrAtlasTextBlob_DEFINED +#include "GrAtlasGlyphCache.h" #include "GrColor.h" #include "GrDrawOpAtlas.h" -#include "GrGlyphCache.h" #include "GrMemoryPool.h" #include "GrTextUtils.h" #include "SkDescriptor.h" @@ -22,13 +22,8 @@ #include "SkSurfaceProps.h" #include "SkTInternalLList.h" -class GrAtlasManager; struct GrDistanceFieldAdjustTable; -struct GrGlyph; -class GrGlyphCache; class GrMemoryPool; -class GrRestrictedAtlasManager; - class SkDrawFilter; class SkTextBlob; class SkTextBlobRunIterator; @@ -206,7 +201,7 @@ public: bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilterBase::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y); - void flush(GrRestrictedAtlasManager*, GrTextUtils::Target*, const SkSurfaceProps& props, + void flush(GrAtlasGlyphCache*, GrTextUtils::Target*, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, const GrTextUtils::Paint& paint, const GrClip& clip, const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, @@ -281,8 +276,8 @@ public: std::unique_ptr test_makeOp(int glyphCount, uint16_t run, uint16_t subRun, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const GrTextUtils::Paint&, const SkSurfaceProps&, - const GrDistanceFieldAdjustTable*, - GrRestrictedAtlasManager*, GrTextUtils::Target*); + const GrDistanceFieldAdjustTable*, GrAtlasGlyphCache*, + GrTextUtils::Target*); private: GrAtlasTextBlob() @@ -511,8 +506,9 @@ private: inline std::unique_ptr makeOp( const Run::SubRunInfo& info, int glyphCount, uint16_t run, uint16_t subRun, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect, - const GrTextUtils::Paint&, const SkSurfaceProps&, - const GrDistanceFieldAdjustTable*, GrRestrictedAtlasManager* , GrTextUtils::Target*); + const GrTextUtils::Paint& paint, const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, GrAtlasGlyphCache* cache, + GrTextUtils::Target*); struct StrokeInfo { SkScalar fFrameWidth; @@ -566,8 +562,7 @@ public: */ VertexRegenerator(GrResourceProvider*, GrAtlasTextBlob*, int runIdx, int subRunIdx, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color, - GrDeferredUploadTarget*, GrGlyphCache*, GrAtlasManager*, - SkAutoGlyphCache*); + GrDeferredUploadTarget*, GrAtlasGlyphCache*, SkAutoGlyphCache*); struct Result { /** @@ -598,8 +593,7 @@ private: const SkMatrix& fViewMatrix; GrAtlasTextBlob* fBlob; GrDeferredUploadTarget* fUploadTarget; - GrGlyphCache* fGlyphCache; - GrAtlasManager* fFullAtlasManager; + GrAtlasGlyphCache* fGlyphCache; SkAutoGlyphCache* fLazyCache; Run* fRun; Run::SubRunInfo* fSubRun; diff --git a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp index 54001c2628..500ae31703 100644 --- a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp +++ b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp @@ -5,7 +5,6 @@ * found in the LICENSE file. */ -#include "GrAtlasManager.h" #include "GrAtlasTextBlob.h" #include "GrTextUtils.h" #include "SkDistanceFieldGen.h" @@ -194,14 +193,13 @@ inline void regen_vertices(char* vertex, const GrGlyph* glyph, size_t vertexStri Regenerator::VertexRegenerator(GrResourceProvider* resourceProvider, GrAtlasTextBlob* blob, int runIdx, int subRunIdx, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color, - GrDeferredUploadTarget* uploadTarget, GrGlyphCache* glyphCache, - GrAtlasManager* fullAtlasManager, SkAutoGlyphCache* lazyCache) + GrDeferredUploadTarget* uploadTarget, GrAtlasGlyphCache* glyphCache, + SkAutoGlyphCache* lazyCache) : fResourceProvider(resourceProvider) , fViewMatrix(viewMatrix) , fBlob(blob) , fUploadTarget(uploadTarget) , fGlyphCache(glyphCache) - , fFullAtlasManager(fullAtlasManager) , fLazyCache(lazyCache) , fRun(&blob->fRuns[runIdx]) , fSubRun(&blob->fRuns[runIdx].fSubRunInfo[subRunIdx]) @@ -209,7 +207,7 @@ Regenerator::VertexRegenerator(GrResourceProvider* resourceProvider, GrAtlasText // Compute translation if any fSubRun->computeTranslation(fViewMatrix, x, y, &fTransX, &fTransY); - // Because the GrGlyphCache may evict the strike a blob depends on using for + // Because the GrAtlasGlyphCache may evict the strike a blob depends on using for // generating its texture coords, we have to track whether or not the strike has // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is // otherwise we have to get the new strike, and use that to get the correct glyphs. @@ -277,17 +275,16 @@ Regenerator::Result Regenerator::doRegen() { glyph = fBlob->fGlyphs[glyphOffset]; SkASSERT(glyph && glyph->fMaskFormat == fSubRun->maskFormat()); - if (!fFullAtlasManager->hasGlyph(glyph) && - !strike->addGlyphToAtlas(fResourceProvider, fUploadTarget, fGlyphCache, - fFullAtlasManager, glyph, + if (!fGlyphCache->hasGlyph(glyph) && + !strike->addGlyphToAtlas(fResourceProvider, fUploadTarget, fGlyphCache, glyph, fLazyCache->get(), fSubRun->maskFormat())) { fBrokenRun = glyphIdx > 0; result.fFinished = false; return result; } auto tokenTracker = fUploadTarget->tokenTracker(); - fFullAtlasManager->addGlyphToBulkAndSetUseToken(fSubRun->bulkUseToken(), glyph, - tokenTracker->nextDrawToken()); + fGlyphCache->addGlyphToBulkAndSetUseToken(fSubRun->bulkUseToken(), glyph, + tokenTracker->nextDrawToken()); } regen_vertices(currVertex, glyph, vertexStride, @@ -305,14 +302,14 @@ Regenerator::Result Regenerator::doRegen() { fSubRun->setStrike(strike); } fSubRun->setAtlasGeneration(fBrokenRun - ? GrDrawOpAtlas::kInvalidAtlasGeneration - : fFullAtlasManager->atlasGeneration(fSubRun->maskFormat())); + ? GrDrawOpAtlas::kInvalidAtlasGeneration + : fGlyphCache->atlasGeneration(fSubRun->maskFormat())); } return result; } Regenerator::Result Regenerator::regenerate() { - uint64_t currentAtlasGen = fFullAtlasManager->atlasGeneration(fSubRun->maskFormat()); + uint64_t currentAtlasGen = fGlyphCache->atlasGeneration(fSubRun->maskFormat()); // If regenerate() is called multiple times then the atlas gen may have changed. So we check // this each time. if (fSubRun->atlasGeneration() != currentAtlasGen) { @@ -355,9 +352,9 @@ Regenerator::Result Regenerator::regenerate() { // set use tokens for all of the glyphs in our subrun. This is only valid if we // have a valid atlas generation - fFullAtlasManager->setUseTokenBulk(*fSubRun->bulkUseToken(), - fUploadTarget->tokenTracker()->nextDrawToken(), - fSubRun->maskFormat()); + fGlyphCache->setUseTokenBulk(*fSubRun->bulkUseToken(), + fUploadTarget->tokenTracker()->nextDrawToken(), + fSubRun->maskFormat()); return result; } } diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp index aadc2dc0c1..06282e103e 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -118,8 +118,7 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t drawFilter); SkScalerContextFlags scalerContextFlags = ComputeScalerContextFlags(target->colorSpaceInfo()); - auto glyphCache = context->contextPriv().getGlyphCache(); - auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager(); + auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache(); GrTextBlobCache* textBlobCache = context->contextPriv().getTextBlobCache(); if (canCache) { @@ -152,7 +151,7 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t // but we'd have to clear the subrun information textBlobCache->remove(cacheBlob.get()); cacheBlob = textBlobCache->makeCachedBlob(blob, key, blurRec, skPaint); - this->regenerateTextBlob(cacheBlob.get(), glyphCache, + this->regenerateTextBlob(cacheBlob.get(), atlasGlyphCache, *context->caps()->shaderCaps(), paint, scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter); } else { @@ -164,7 +163,7 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob); sk_sp sanityBlob(textBlobCache->makeBlob(glyphCount, runCount)); sanityBlob->setupKey(key, blurRec, skPaint); - this->regenerateTextBlob(sanityBlob.get(), glyphCache, + this->regenerateTextBlob(sanityBlob.get(), atlasGlyphCache, *context->caps()->shaderCaps(), paint, scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter); GrAtlasTextBlob::AssertEqual(*sanityBlob, *cacheBlob); @@ -176,17 +175,17 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t } else { cacheBlob = textBlobCache->makeBlob(blob); } - this->regenerateTextBlob(cacheBlob.get(), glyphCache, + this->regenerateTextBlob(cacheBlob.get(), atlasGlyphCache, *context->caps()->shaderCaps(), paint, scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter); } - cacheBlob->flush(restrictedAtlasManager, target, props, fDistanceAdjustTable.get(), paint, + cacheBlob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, clip, viewMatrix, clipBounds, x, y); } void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, - GrGlyphCache* glyphCache, + GrAtlasGlyphCache* fontCache, const GrShaderCaps& shaderCaps, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, @@ -212,21 +211,21 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, if (this->canDrawAsDistanceFields(runPaint, viewMatrix, props, shaderCaps)) { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: { - this->drawDFText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, + this->drawDFText(cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, viewMatrix, (const char*)it.glyphs(), textLen, x + offset.x(), y + offset.y()); break; } case SkTextBlob::kHorizontal_Positioning: { SkPoint dfOffset = SkPoint::Make(x, y + offset.y()); - this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint, + this->drawDFPosText(cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 1, dfOffset); break; } case SkTextBlob::kFull_Positioning: { SkPoint dfOffset = SkPoint::Make(x, y); - this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint, + this->drawDFPosText(cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2, dfOffset); break; @@ -235,17 +234,17 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, } else { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: - DrawBmpText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, + DrawBmpText(cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, viewMatrix, (const char*)it.glyphs(), textLen, x + offset.x(), y + offset.y()); break; case SkTextBlob::kHorizontal_Positioning: - DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, + DrawBmpPosText(cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y())); break; case SkTextBlob::kFull_Positioning: - DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, + DrawBmpPosText(cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2, SkPoint::Make(x, y)); break; @@ -256,7 +255,7 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, inline sk_sp GrAtlasTextContext::makeDrawTextBlob(GrTextBlobCache* blobCache, - GrGlyphCache* glyphCache, + GrAtlasGlyphCache* fontCache, const GrShaderCaps& shaderCaps, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, @@ -273,10 +272,10 @@ GrAtlasTextContext::makeDrawTextBlob(GrTextBlobCache* blobCache, blob->setRunPaintFlags(0, paint.skPaint().getFlags()); if (this->canDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) { - this->drawDFText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, + this->drawDFText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, x, y); } else { - DrawBmpText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, text, + DrawBmpText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, x, y); } return blob; @@ -284,7 +283,7 @@ GrAtlasTextContext::makeDrawTextBlob(GrTextBlobCache* blobCache, inline sk_sp GrAtlasTextContext::makeDrawPosTextBlob(GrTextBlobCache* blobCache, - GrGlyphCache* glyphCache, + GrAtlasGlyphCache* fontCache, const GrShaderCaps& shaderCaps, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, @@ -303,11 +302,11 @@ GrAtlasTextContext::makeDrawPosTextBlob(GrTextBlobCache* blobCache, blob->setRunPaintFlags(0, paint.skPaint().getFlags()); if (this->canDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) { - this->drawDFPosText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, + this->drawDFPosText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset); } else { - DrawBmpPosText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, - text, byteLength, pos, scalarsPerPosition, offset); + DrawBmpPosText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix, text, + byteLength, pos, scalarsPerPosition, offset); } return blob; } @@ -321,18 +320,17 @@ void GrAtlasTextContext::drawText(GrContext* context, GrTextUtils::Target* targe return; } - auto glyphCache = context->contextPriv().getGlyphCache(); - auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager(); + auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache(); auto textBlobCache = context->contextPriv().getTextBlobCache(); GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo()); sk_sp blob( - this->makeDrawTextBlob(textBlobCache, glyphCache, + this->makeDrawTextBlob(textBlobCache, atlasGlyphCache, *context->caps()->shaderCaps(), paint, ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text, byteLength, x, y)); if (blob) { - blob->flush(restrictedAtlasManager, target, props, fDistanceAdjustTable.get(), paint, + blob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, clip, viewMatrix, regionClipBounds, x, y); } } @@ -348,23 +346,22 @@ void GrAtlasTextContext::drawPosText(GrContext* context, GrTextUtils::Target* ta return; } - auto glyphCache = context->contextPriv().getGlyphCache(); - auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager(); + auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache(); auto textBlobCache = context->contextPriv().getTextBlobCache(); sk_sp blob(this->makeDrawPosTextBlob( - textBlobCache, glyphCache, + textBlobCache, atlasGlyphCache, *context->caps()->shaderCaps(), paint, ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text, byteLength, pos, scalarsPerPosition, offset)); if (blob) { - blob->flush(restrictedAtlasManager, target, props, fDistanceAdjustTable.get(), paint, + blob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, clip, viewMatrix, regionClipBounds, offset.fX, offset.fY); } } void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, - GrGlyphCache* glyphCache, const SkSurfaceProps& props, + GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], @@ -380,7 +377,7 @@ void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, blob->setHasBitmap(); if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) { - DrawBmpTextAsPaths(blob, runIndex, glyphCache, props, paint, scalerContextFlags, viewMatrix, + DrawBmpTextAsPaths(blob, runIndex, fontCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, x, y); return; } @@ -390,7 +387,7 @@ void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, viewMatrix, paint.skPaint().getTextAlign(), cache, [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { position += rounding; - BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike, + BmpAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, SkScalarFloorToScalar(position.fX), SkScalarFloorToScalar(position.fY), paint.filteredPremulColor(), cache, @@ -401,7 +398,7 @@ void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, } void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, - GrGlyphCache* glyphCache, const SkSurfaceProps& props, + GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, @@ -419,7 +416,7 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, blob->setHasBitmap(); if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) { - DrawBmpPosTextAsPaths(blob, runIndex, glyphCache, props, paint, scalerContextFlags, + DrawBmpPosTextAsPaths(blob, runIndex, fontCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset); return; } @@ -432,7 +429,7 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, scalarsPerPosition, paint.skPaint().getTextAlign(), cache, [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { position += rounding; - BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, + BmpAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, SkScalarFloorToScalar(position.fX), SkScalarFloorToScalar(position.fY), paint.filteredPremulColor(), cache, SK_Scalar1); @@ -442,7 +439,7 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, } void GrAtlasTextContext::DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex, - GrGlyphCache* glyphCache, + GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, const GrTextUtils::Paint& origPaint, SkScalerContextFlags scalerContextFlags, @@ -460,7 +457,7 @@ void GrAtlasTextContext::DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex, GrTextUtils::PathTextIter iter(text, byteLength, pathPaint, true); FallbackTextHelper fallbackTextHelper(viewMatrix, pathPaint.getTextSize(), - glyphCache->getGlyphSizeLimit(), + fontCache->getGlyphSizeLimit(), iter.getPathScale()); const SkGlyph* iterGlyph; @@ -477,11 +474,11 @@ void GrAtlasTextContext::DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex, lastText = iter.getText(); } - fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, origPaint, scalerContextFlags); + fallbackTextHelper.drawText(blob, runIndex, fontCache, props, origPaint, scalerContextFlags); } void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runIndex, - GrGlyphCache* glyphCache, + GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, const GrTextUtils::Paint& origPaint, SkScalerContextFlags scalerContextFlags, @@ -500,7 +497,7 @@ void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runInd SkPaint pathPaint(origPaint); SkScalar matrixScale = pathPaint.setupForAsPaths(); FallbackTextHelper fallbackTextHelper(viewMatrix, pathPaint.getTextSize(), matrixScale, - glyphCache->getGlyphSizeLimit()); + fontCache->getGlyphSizeLimit()); // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. pathPaint.setStyle(SkPaint::kFill_Style); @@ -537,23 +534,23 @@ void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runInd pos += scalarsPerPosition; } - fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, origPaint, scalerContextFlags); + fallbackTextHelper.drawText(blob, runIndex, fontCache, props, origPaint, scalerContextFlags); } void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, - GrGlyphCache* grGlyphCache, GrAtlasTextStrike** strike, + GrAtlasGlyphCache* fontCache, GrAtlasTextStrike** strike, const SkGlyph& skGlyph, SkScalar sx, SkScalar sy, - GrColor color, SkGlyphCache* skGlyphCache, + GrColor color, SkGlyphCache* glyphCache, SkScalar textRatio) { if (!*strike) { - *strike = grGlyphCache->getStrike(skGlyphCache); + *strike = fontCache->getStrike(glyphCache); } GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), skGlyph.getSubXFixed(), skGlyph.getSubYFixed(), GrGlyph::kCoverage_MaskStyle); - GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, skGlyphCache); + GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, glyphCache); if (!glyph) { return; } @@ -573,7 +570,7 @@ void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, SkRect glyphRect = SkRect::MakeXYWH(sx + dx, sy + dy, width, height); - blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, skGlyphCache, skGlyph, sx, sy, + blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, glyphCache, skGlyph, sx, sy, textRatio, true); } @@ -673,7 +670,7 @@ void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob, } void GrAtlasTextContext::drawDFText(GrAtlasTextBlob* blob, int runIndex, - GrGlyphCache* glyphCache, const SkSurfaceProps& props, + GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], @@ -743,12 +740,12 @@ void GrAtlasTextContext::drawDFText(GrAtlasTextBlob* blob, int runIndex, y -= alignY; SkPoint offset = SkPoint::Make(x, y); - this->drawDFPosText(blob, runIndex, glyphCache, props, paint, scalerContextFlags, viewMatrix, + this->drawDFPosText(blob, runIndex, fontCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, positions.begin(), 2, offset); } void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, - GrGlyphCache* glyphCache, const SkSurfaceProps& props, + GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], @@ -774,7 +771,7 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, FallbackTextHelper fallbackTextHelper(viewMatrix, paint.skPaint().getTextSize(), - glyphCache->getGlyphSizeLimit(), + fontCache->getGlyphSizeLimit(), textRatio); GrAtlasTextStrike* currStrike = nullptr; @@ -803,7 +800,7 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkFloatToScalar(glyph.fAdvanceY) * alignMul * textRatio; if (glyph.fMaskFormat != SkMask::kARGB32_Format) { - DfAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, glyphPos.fX, + DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, glyphPos.fX, glyphPos.fY, paint.filteredPremulColor(), cache, textRatio); } else { // can't append color glyph to SDF batch, send to fallback @@ -815,24 +812,25 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkGlyphCache::AttachCache(cache); - fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, paint, scalerContextFlags); + fallbackTextHelper.drawText(blob, runIndex, fontCache, props, paint, + scalerContextFlags); } // TODO: merge with BmpAppendGlyph void GrAtlasTextContext::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, - GrGlyphCache* grGlyphCache, GrAtlasTextStrike** strike, + GrAtlasGlyphCache* cache, GrAtlasTextStrike** strike, const SkGlyph& skGlyph, SkScalar sx, SkScalar sy, - GrColor color, SkGlyphCache* skGlyphCache, + GrColor color, SkGlyphCache* glyphCache, SkScalar textRatio) { if (!*strike) { - *strike = grGlyphCache->getStrike(skGlyphCache); + *strike = cache->getStrike(glyphCache); } GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), skGlyph.getSubXFixed(), skGlyph.getSubYFixed(), GrGlyph::kDistance_MaskStyle); - GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, skGlyphCache); + GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, glyphCache); if (!glyph) { return; } @@ -848,7 +846,7 @@ void GrAtlasTextContext::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, height *= textRatio; SkRect glyphRect = SkRect::MakeXYWH(sx + dx, sy + dy, width, height); - blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, skGlyphCache, skGlyph, sx, sy, + blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, glyphCache, skGlyph, sx, sy, textRatio, false); } @@ -873,7 +871,7 @@ void GrAtlasTextContext::FallbackTextHelper::appendText(const SkGlyph& glyph, in } void GrAtlasTextContext::FallbackTextHelper::drawText(GrAtlasTextBlob* blob, int runIndex, - GrGlyphCache* glyphCache, + GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags) { @@ -911,7 +909,7 @@ void GrAtlasTextContext::FallbackTextHelper::drawText(GrAtlasTextBlob* blob, int SkPoint* glyphPos = fFallbackPos.begin(); while (text < stop) { const SkGlyph& glyph = glyphCacheProc(cache, &text); - GrAtlasTextContext::BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, + GrAtlasTextContext::BmpAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, glyphPos->fX, glyphPos->fY, textColor, cache, textRatio); glyphPos++; @@ -964,19 +962,18 @@ GR_DRAW_OP_TEST_DEFINE(GrAtlasTextOp) { SkScalar x = SkIntToScalar(xInt); SkScalar y = SkIntToScalar(yInt); - auto glyphCache = context->contextPriv().getGlyphCache(); - auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager(); + auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache(); // right now we don't handle textblobs, nor do we handle drawPosText. Since we only intend to // test the text op with this unit test, that is okay. sk_sp blob(gTextContext->makeDrawTextBlob( - context->contextPriv().getTextBlobCache(), glyphCache, + context->contextPriv().getTextBlobCache(), atlasGlyphCache, *context->caps()->shaderCaps(), utilsPaint, GrAtlasTextContext::kTextBlobOpScalerContextFlags, viewMatrix, gSurfaceProps, text, static_cast(textLen), x, y)); return blob->test_makeOp(textLen, 0, 0, viewMatrix, x, y, utilsPaint, gSurfaceProps, - gTextContext->dfAdjustTable(), restrictedAtlasManager, + gTextContext->dfAdjustTable(), atlasGlyphCache, rtc->textTarget()); } diff --git a/src/gpu/text/GrAtlasTextContext.h b/src/gpu/text/GrAtlasTextContext.h index 37b7de5357..207dd67206 100644 --- a/src/gpu/text/GrAtlasTextContext.h +++ b/src/gpu/text/GrAtlasTextContext.h @@ -74,8 +74,9 @@ private: } void appendText(const SkGlyph& glyph, int count, const char* text, SkPoint glyphPos); - void drawText(GrAtlasTextBlob* blob, int runIndex, GrGlyphCache*, const SkSurfaceProps&, - const GrTextUtils::Paint&, SkScalerContextFlags); + void drawText(GrAtlasTextBlob* blob, int runIndex, + GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, + const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags); private: SkTDArray fFallbackTxt; @@ -95,7 +96,7 @@ private: // Determines if we need to use fake gamma (and contrast boost): static SkScalerContextFlags ComputeScalerContextFlags(const GrColorSpaceInfo&); void regenerateTextBlob(GrAtlasTextBlob* bmp, - GrGlyphCache*, + GrAtlasGlyphCache*, const GrShaderCaps&, const GrTextUtils::Paint&, SkScalerContextFlags scalerContextFlags, @@ -106,7 +107,7 @@ private: static bool HasLCD(const SkTextBlob*); - sk_sp makeDrawTextBlob(GrTextBlobCache*, GrGlyphCache*, + sk_sp makeDrawTextBlob(GrTextBlobCache*, GrAtlasGlyphCache*, const GrShaderCaps&, const GrTextUtils::Paint&, SkScalerContextFlags scalerContextFlags, @@ -115,7 +116,7 @@ private: const char text[], size_t byteLength, SkScalar x, SkScalar y) const; - sk_sp makeDrawPosTextBlob(GrTextBlobCache*, GrGlyphCache*, + sk_sp makeDrawPosTextBlob(GrTextBlobCache*, GrAtlasGlyphCache*, const GrShaderCaps&, const GrTextUtils::Paint&, SkScalerContextFlags scalerContextFlags, @@ -127,24 +128,24 @@ private: const SkPoint& offset) const; // Functions for appending BMP text to GrAtlasTextBlob - static void DrawBmpText(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, + static void DrawBmpText(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y); - static void DrawBmpPosText(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, + static void DrawBmpPosText(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset); - static void DrawBmpTextAsPaths(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, + static void DrawBmpTextAsPaths(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y); - static void DrawBmpPosTextAsPaths(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, + static void DrawBmpPosTextAsPaths(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, @@ -156,12 +157,12 @@ private: bool canDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const GrShaderCaps& caps) const; - void drawDFText(GrAtlasTextBlob* blob, int runIndex, GrGlyphCache*, const SkSurfaceProps&, + void drawDFText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y) const; - void drawDFPosText(GrAtlasTextBlob* blob, int runIndex, GrGlyphCache*, + void drawDFPosText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], @@ -173,11 +174,11 @@ private: SkScalar* textRatio, const SkMatrix& viewMatrix) const; - static void BmpAppendGlyph(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, + static void BmpAppendGlyph(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, GrAtlasTextStrike**, const SkGlyph&, SkScalar sx, SkScalar sy, GrColor color, SkGlyphCache*, SkScalar textRatio); - static void DfAppendGlyph(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, + static void DfAppendGlyph(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, GrAtlasTextStrike**, const SkGlyph&, SkScalar sx, SkScalar sy, GrColor color, SkGlyphCache* cache, SkScalar textRatio); diff --git a/src/gpu/text/GrGlyphCache.cpp b/src/gpu/text/GrGlyphCache.cpp deleted file mode 100644 index d4440897bc..0000000000 --- a/src/gpu/text/GrGlyphCache.cpp +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrAtlasManager.h" -#include "GrDistanceFieldGenFromVector.h" -#include "GrGlyphCache.h" - -#include "SkAutoMalloc.h" -#include "SkDistanceFieldGen.h" - -GrGlyphCache::GrGlyphCache() - : fPreserveStrike(nullptr) - , fGlyphSizeLimit(0) { -} - -GrGlyphCache::~GrGlyphCache() { - StrikeHash::Iter iter(&fCache); - while (!iter.done()) { - (*iter).fIsAbandoned = true; - (*iter).unref(); - ++iter; - } -} - -void GrGlyphCache::freeAll() { - StrikeHash::Iter iter(&fCache); - while (!iter.done()) { - (*iter).fIsAbandoned = true; - (*iter).unref(); - ++iter; - } - fCache.rewind(); -} - -void GrGlyphCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) { - GrGlyphCache* glyphCache = reinterpret_cast(ptr); - - StrikeHash::Iter iter(&glyphCache->fCache); - for (; !iter.done(); ++iter) { - GrAtlasTextStrike* strike = &*iter; - strike->removeID(id); - - // clear out any empty strikes. We will preserve the strike whose call to addToAtlas - // triggered the eviction - if (strike != glyphCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) { - glyphCache->fCache.remove(GrAtlasTextStrike::GetKey(*strike)); - strike->fIsAbandoned = true; - strike->unref(); - } - } -} - -static inline GrMaskFormat get_packed_glyph_mask_format(const SkGlyph& glyph) { - SkMask::Format format = static_cast(glyph.fMaskFormat); - switch (format) { - case SkMask::kBW_Format: - // fall through to kA8 -- we store BW glyphs in our 8-bit cache - case SkMask::kA8_Format: - return kA8_GrMaskFormat; - case SkMask::k3D_Format: - return kA8_GrMaskFormat; // ignore the mul and add planes, just use the mask - case SkMask::kLCD16_Format: - return kA565_GrMaskFormat; - case SkMask::kARGB32_Format: - return kARGB_GrMaskFormat; - default: - SkDEBUGFAIL("unsupported SkMask::Format"); - return kA8_GrMaskFormat; - } -} - -static inline bool get_packed_glyph_bounds(SkGlyphCache* cache, const SkGlyph& glyph, - SkIRect* bounds) { -#if 1 - // crbug:510931 - // Retrieving the image from the cache can actually change the mask format. - cache->findImage(glyph); -#endif - bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight); - - return true; -} - -static inline bool get_packed_glyph_df_bounds(SkGlyphCache* cache, const SkGlyph& glyph, - SkIRect* bounds) { -#if 1 - // crbug:510931 - // Retrieving the image from the cache can actually change the mask format. - cache->findImage(glyph); -#endif - bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight); - bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad); - - return true; -} - -// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to -// A8, RGB565, or RGBA8888. -template -static void expand_bits(INT_TYPE* dst, - const uint8_t* src, - int width, - int height, - int dstRowBytes, - int srcRowBytes) { - for (int i = 0; i < height; ++i) { - int rowWritesLeft = width; - const uint8_t* s = src; - INT_TYPE* d = dst; - while (rowWritesLeft > 0) { - unsigned mask = *s++; - for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) { - *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0; - } - } - dst = reinterpret_cast(reinterpret_cast(dst) + dstRowBytes); - src += srcRowBytes; - } -} - -static bool get_packed_glyph_image(SkGlyphCache* cache, const SkGlyph& glyph, int width, - int height, int dstRB, GrMaskFormat expectedMaskFormat, - void* dst) { - SkASSERT(glyph.fWidth == width); - SkASSERT(glyph.fHeight == height); - const void* src = cache->findImage(glyph); - if (nullptr == src) { - return false; - } - - // crbug:510931 - // Retrieving the image from the cache can actually change the mask format. This case is very - // uncommon so for now we just draw a clear box for these glyphs. - if (get_packed_glyph_mask_format(glyph) != expectedMaskFormat) { - const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat); - for (int y = 0; y < height; y++) { - sk_bzero(dst, width * bpp); - dst = (char*)dst + dstRB; - } - return true; - } - - int srcRB = glyph.rowBytes(); - // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to - // check the glyph's format, not the strike's format, and to be able to convert to any of the - // GrMaskFormats. - if (SkMask::kBW_Format == glyph.fMaskFormat) { - // expand bits to our mask type - const uint8_t* bits = reinterpret_cast(src); - switch (expectedMaskFormat) { - case kA8_GrMaskFormat:{ - uint8_t* bytes = reinterpret_cast(dst); - expand_bits(bytes, bits, width, height, dstRB, srcRB); - break; - } - case kA565_GrMaskFormat: { - uint16_t* rgb565 = reinterpret_cast(dst); - expand_bits(rgb565, bits, width, height, dstRB, srcRB); - break; - } - default: - SK_ABORT("Invalid GrMaskFormat"); - } - } else if (srcRB == dstRB) { - memcpy(dst, src, dstRB * height); - } else { - const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat); - for (int y = 0; y < height; y++) { - memcpy(dst, src, width * bbp); - src = (const char*)src + srcRB; - dst = (char*)dst + dstRB; - } - } - return true; -} - -static bool get_packed_glyph_df_image(SkGlyphCache* cache, const SkGlyph& glyph, - int width, int height, void* dst) { - SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width); - SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height); - -#ifndef SK_USE_LEGACY_DISTANCE_FIELDS - const SkPath* path = cache->findPath(glyph); - if (nullptr == path) { - return false; - } - - SkDEBUGCODE(SkRect glyphBounds = SkRect::MakeXYWH(glyph.fLeft, - glyph.fTop, - glyph.fWidth, - glyph.fHeight)); - SkASSERT(glyphBounds.contains(path->getBounds())); - - // now generate the distance field - SkASSERT(dst); - SkMatrix drawMatrix; - drawMatrix.setTranslate((SkScalar)-glyph.fLeft, (SkScalar)-glyph.fTop); - - // Generate signed distance field directly from SkPath - bool succeed = GrGenerateDistanceFieldFromPath((unsigned char*)dst, - *path, drawMatrix, - width, height, width * sizeof(unsigned char)); - - if (!succeed) { -#endif - const void* image = cache->findImage(glyph); - if (nullptr == image) { - return false; - } - - // now generate the distance field - SkASSERT(dst); - SkMask::Format maskFormat = static_cast(glyph.fMaskFormat); - if (SkMask::kA8_Format == maskFormat) { - // make the distance field from the image - SkGenerateDistanceFieldFromA8Image((unsigned char*)dst, - (unsigned char*)image, - glyph.fWidth, glyph.fHeight, - glyph.rowBytes()); - } else if (SkMask::kBW_Format == maskFormat) { - // make the distance field from the image - SkGenerateDistanceFieldFromBWImage((unsigned char*)dst, - (unsigned char*)image, - glyph.fWidth, glyph.fHeight, - glyph.rowBytes()); - } else { - return false; - } -#ifndef SK_USE_LEGACY_DISTANCE_FIELDS - } -#endif - return true; -} - -/////////////////////////////////////////////////////////////////////////////// - -/* - The text strike is specific to a given font/style/matrix setup, which is - represented by the GrHostFontScaler object we are given in getGlyph(). - - We map a 32bit glyphID to a GrGlyph record, which in turn points to a - atlas and a position within that texture. - */ - -GrAtlasTextStrike::GrAtlasTextStrike(const SkDescriptor& key) - : fFontScalerKey(key) - , fPool(9/*start allocations at 512 bytes*/) - , fAtlasedGlyphs(0) - , fIsAbandoned(false) {} - -GrAtlasTextStrike::~GrAtlasTextStrike() { - SkTDynamicHash::Iter iter(&fCache); - while (!iter.done()) { - (*iter).reset(); - ++iter; - } -} - -GrGlyph* GrAtlasTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed, - SkGlyphCache* cache) { - SkIRect bounds; - if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(packed)) { - if (!get_packed_glyph_df_bounds(cache, skGlyph, &bounds)) { - return nullptr; - } - } else { - if (!get_packed_glyph_bounds(cache, skGlyph, &bounds)) { - return nullptr; - } - } - GrMaskFormat format = get_packed_glyph_mask_format(skGlyph); - - GrGlyph* glyph = fPool.make(); - glyph->init(packed, bounds, format); - fCache.add(glyph); - return glyph; -} - -void GrAtlasTextStrike::removeID(GrDrawOpAtlas::AtlasID id) { - SkTDynamicHash::Iter iter(&fCache); - while (!iter.done()) { - if (id == (*iter).fID) { - (*iter).fID = GrDrawOpAtlas::kInvalidAtlasID; - fAtlasedGlyphs--; - SkASSERT(fAtlasedGlyphs >= 0); - } - ++iter; - } -} - -bool GrAtlasTextStrike::addGlyphToAtlas(GrResourceProvider* resourceProvider, - GrDeferredUploadTarget* target, - GrGlyphCache* glyphCache, - GrAtlasManager* fullAtlasManager, - GrGlyph* glyph, - SkGlyphCache* cache, - GrMaskFormat expectedMaskFormat) { - SkASSERT(glyph); - SkASSERT(cache); - SkASSERT(fCache.find(glyph->fPackedID)); - - int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat); - - size_t size = glyph->fBounds.area() * bytesPerPixel; - SkAutoSMalloc<1024> storage(size); - - const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID); - if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) { - if (!get_packed_glyph_df_image(cache, skGlyph, glyph->width(), glyph->height(), - storage.get())) { - return false; - } - } else { - if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(), - glyph->width() * bytesPerPixel, expectedMaskFormat, - storage.get())) { - return false; - } - } - - bool success = fullAtlasManager->addToAtlas(resourceProvider, glyphCache, this, - &glyph->fID, target, expectedMaskFormat, - glyph->width(), glyph->height(), - storage.get(), &glyph->fAtlasLocation); - if (success) { - SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID); - fAtlasedGlyphs++; - } - return success; -} diff --git a/src/gpu/text/GrGlyphCache.h b/src/gpu/text/GrGlyphCache.h deleted file mode 100644 index 169e4b30a5..0000000000 --- a/src/gpu/text/GrGlyphCache.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrAtlasGlyphCache_DEFINED -#define GrAtlasGlyphCache_DEFINED - -#include "GrDrawOpAtlas.h" -#include "GrGlyph.h" -#include "SkArenaAlloc.h" -#include "SkGlyphCache.h" -#include "SkTDynamicHash.h" - -class GrGlyphCache; -class GrAtlasManager; -class GrGpu; - -/** - * The GrAtlasTextStrike manages a pool of CPU backing memory for GrGlyphs. This backing memory - * is indexed by a PackedID and SkGlyphCache. The SkGlyphCache is what actually creates the mask. - * The GrAtlasTextStrike may outlive the generating SkGlyphCache. However, it retains a copy - * of it's SkDescriptor as a key to access (or regenerate) the SkGlyphCache. GrAtlasTextStrike are - * created by and owned by a GrGlyphCache. - */ -class GrAtlasTextStrike : public SkNVRefCnt { -public: - GrAtlasTextStrike(const SkDescriptor& fontScalerKey); - ~GrAtlasTextStrike(); - - inline GrGlyph* getGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed, - SkGlyphCache* cache) { - GrGlyph* glyph = fCache.find(packed); - if (nullptr == glyph) { - glyph = this->generateGlyph(skGlyph, packed, cache); - } - return glyph; - } - - // This variant of the above function is called by GrAtlasTextOp. At this point, it is possible - // that the maskformat of the glyph differs from what we expect. In these cases we will just - // draw a clear square. - // skbug:4143 crbug:510931 - inline GrGlyph* getGlyph(GrGlyph::PackedID packed, - GrMaskFormat expectedMaskFormat, - SkGlyphCache* cache) { - GrGlyph* glyph = fCache.find(packed); - if (nullptr == glyph) { - // We could return this to the caller, but in practice it adds code complexity for - // potentially little benefit(ie, if the glyph is not in our font cache, then its not - // in the atlas and we're going to be doing a texture upload anyways). - const SkGlyph& skGlyph = GrToSkGlyph(cache, packed); - glyph = this->generateGlyph(skGlyph, packed, cache); - glyph->fMaskFormat = expectedMaskFormat; - } - return glyph; - } - - // returns true if glyph successfully added to texture atlas, false otherwise. If the glyph's - // mask format has changed, then addGlyphToAtlas will draw a clear box. This will almost never - // happen. - // TODO we can handle some of these cases if we really want to, but the long term solution is to - // get the actual glyph image itself when we get the glyph metrics. - bool addGlyphToAtlas(GrResourceProvider*, GrDeferredUploadTarget*, GrGlyphCache*, - GrAtlasManager*, GrGlyph*, - SkGlyphCache*, GrMaskFormat expectedMaskFormat); - - // testing - int countGlyphs() const { return fCache.count(); } - - // remove any references to this plot - void removeID(GrDrawOpAtlas::AtlasID); - - // If a TextStrike is abandoned by the cache, then the caller must get a new strike - bool isAbandoned() const { return fIsAbandoned; } - - static const SkDescriptor& GetKey(const GrAtlasTextStrike& ts) { - return *ts.fFontScalerKey.getDesc(); - } - - static uint32_t Hash(const SkDescriptor& desc) { return desc.getChecksum(); } - -private: - SkTDynamicHash fCache; - SkAutoDescriptor fFontScalerKey; - SkArenaAlloc fPool{512}; - - int fAtlasedGlyphs; - bool fIsAbandoned; - - static const SkGlyph& GrToSkGlyph(SkGlyphCache* cache, GrGlyph::PackedID id) { - return cache->getGlyphIDMetrics(GrGlyph::UnpackID(id), - GrGlyph::UnpackFixedX(id), - GrGlyph::UnpackFixedY(id)); - } - - GrGlyph* generateGlyph(const SkGlyph&, GrGlyph::PackedID, SkGlyphCache*); - - friend class GrGlyphCache; -}; - -/** - * GrGlyphCache manages strikes which are indexed by a SkGlyphCache. These strikes can then be - * used to generate individual Glyph Masks. - */ -class GrGlyphCache { -public: - GrGlyphCache(); - ~GrGlyphCache(); - - void setGlyphSizeLimit(SkScalar sizeLimit) { fGlyphSizeLimit = sizeLimit; } - SkScalar getGlyphSizeLimit() const { return fGlyphSizeLimit; } - - void setStrikeToPreserve(GrAtlasTextStrike* strike) { fPreserveStrike = strike; } - - // The user of the cache may hold a long-lived ref to the returned strike. However, actions by - // another client of the cache may cause the strike to be purged while it is still reffed. - // Therefore, the caller must check GrAtlasTextStrike::isAbandoned() if there are other - // interactions with the cache since the strike was received. - inline GrAtlasTextStrike* getStrike(const SkGlyphCache* cache) { - GrAtlasTextStrike* strike = fCache.find(cache->getDescriptor()); - if (nullptr == strike) { - strike = this->generateStrike(cache); - } - return strike; - } - - void freeAll(); - - static void HandleEviction(GrDrawOpAtlas::AtlasID, void*); - -private: - GrAtlasTextStrike* generateStrike(const SkGlyphCache* cache) { - GrAtlasTextStrike* strike = new GrAtlasTextStrike(cache->getDescriptor()); - fCache.add(strike); - return strike; - } - - using StrikeHash = SkTDynamicHash; - - StrikeHash fCache; - GrAtlasTextStrike* fPreserveStrike; - SkScalar fGlyphSizeLimit; -}; - -#endif diff --git a/src/gpu/text/GrTextUtils.h b/src/gpu/text/GrTextUtils.h index 69421c2474..5fe38fe773 100644 --- a/src/gpu/text/GrTextUtils.h +++ b/src/gpu/text/GrTextUtils.h @@ -16,13 +16,13 @@ #include "SkTextToPathIter.h" #include "SkTLazy.h" +class GrAtlasGlyphCache; class GrAtlasTextBlob; class GrAtlasTextOp; class GrAtlasTextStrike; class GrClip; class GrColorSpaceXform; class GrContext; -class GrGlyphCache; class GrPaint; class GrShaderCaps; class SkColorSpace; diff --git a/tests/DrawOpAtlasTest.cpp b/tests/DrawOpAtlasTest.cpp index 7e35a07726..a34618e38f 100644 --- a/tests/DrawOpAtlasTest.cpp +++ b/tests/DrawOpAtlasTest.cpp @@ -11,7 +11,7 @@ #include "GrContextPriv.h" #include "Test.h" -#include "text/GrGlyphCache.h" +#include "text/GrAtlasGlyphCache.h" static const int kNumPlots = 2; static const int kPlotSize = 32; diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp index c483a22aac..c6d3bbe2ef 100644 --- a/tools/gpu/GrTest.cpp +++ b/tools/gpu/GrTest.cpp @@ -26,7 +26,7 @@ #include "SkMathPriv.h" #include "SkString.h" #include "ops/GrMeshDrawOp.h" -#include "text/GrGlyphCache.h" +#include "text/GrAtlasGlyphCache.h" #include "text/GrTextBlobCache.h" namespace GrTest { @@ -94,7 +94,7 @@ void GrContext::setTextBlobCacheLimit_ForTesting(size_t bytes) { } void GrContext::setTextContextAtlasSizes_ForTesting(const GrDrawOpAtlasConfig* configs) { - fFullAtlasManager->setAtlasSizes_ForTesting(configs); + fAtlasGlyphCache->setAtlasSizes_ForTesting(configs); } /////////////////////////////////////////////////////////////////////////////// @@ -147,11 +147,11 @@ void GrContext::printGpuStats() const { SkDebugf("%s", out.c_str()); } -sk_sp GrContext::getFontAtlasImage_ForTesting(GrMaskFormat format, unsigned int index) { - auto restrictedAtlasManager = this->contextPriv().getRestrictedAtlasManager(); +sk_sp GrContext::getFontAtlasImage_ForTesting(GrMaskFormat format, uint32_t index) { + GrAtlasGlyphCache* cache = this->contextPriv().getAtlasGlyphCache(); unsigned int numProxies; - const sk_sp* proxies = restrictedAtlasManager->getProxies(format, &numProxies); + const sk_sp* proxies = cache->getProxies(format, &numProxies); if (index >= numProxies || !proxies[index]) { return nullptr; } -- cgit v1.2.3