diff options
author | Robert Phillips <robertphillips@google.com> | 2018-02-27 16:43:18 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-02-27 22:05:55 +0000 |
commit | acf17904d6286f2a63a5d895541804d0ea1be646 (patch) | |
tree | efafdb48995fd150c37b1442bf58295d4d66cd89 | |
parent | c420525bd4cde4cdac471880d080d8c742307788 (diff) |
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 <robertphillips@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
27 files changed, 788 insertions, 609 deletions
diff --git a/gn/gpu.gni b/gn/gpu.gni index a34e62b6b4..27a50a9a70 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/GrAtlasGlyphCache.cpp", - "$_src/gpu/text/GrAtlasGlyphCache.h", + "$_src/gpu/text/GrAtlasManager.cpp", + "$_src/gpu/text/GrAtlasManager.h", "$_src/gpu/text/GrAtlasTextBlob.cpp", "$_src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp", "$_src/gpu/text/GrAtlasTextBlob.h", @@ -401,6 +401,8 @@ 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 914983c2ec..ff4ec5f677 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -16,7 +16,7 @@ #include "../private/GrSingleOwner.h" #include "GrContextOptions.h" -class GrAtlasGlyphCache; +class GrAtlasManager; class GrBackendFormat; class GrBackendSemaphore; class GrContextPriv; @@ -25,6 +25,7 @@ class GrDrawingManager; struct GrDrawOpAtlasConfig; class GrFragmentProcessor; struct GrGLInterface; +class GrGlyphCache; class GrGpu; class GrIndexBuffer; struct GrMockOptions; @@ -366,7 +367,8 @@ private: sk_sp<GrContextThreadSafeProxy> fThreadSafeProxy; - GrAtlasGlyphCache* fAtlasGlyphCache; + GrGlyphCache* fGlyphCache; + GrAtlasManager* fFullAtlasManager; std::unique_ptr<GrTextBlobCache> fTextBlobCache; bool fDisableGpuYUVConversion; diff --git a/src/atlastext/SkAtlasTextTarget.cpp b/src/atlastext/SkAtlasTextTarget.cpp index f553ffad96..9da5fd1e3d 100644 --- a/src/atlastext/SkAtlasTextTarget.cpp +++ b/src/atlastext/SkAtlasTextTarget.cpp @@ -181,20 +181,17 @@ void GrAtlasTextOp::finalizeForTextTarget(uint32_t color, const GrCaps& caps) { void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target) { FlushInfo flushInfo; - SkAutoGlyphCache glyphCache; + SkAutoGlyphCache autoGlyphCache; auto& context = target->context()->internal(); - auto atlasGlyphCache = context.grContext()->contextPriv().getAtlasGlyphCache(); + auto glyphCache = context.grContext()->contextPriv().getGlyphCache(); + auto fullAtlasManager = context.grContext()->contextPriv().getFullAtlasManager(); 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, atlasGlyphCache, &glyphCache); + &context, glyphCache, fullAtlasManager, &autoGlyphCache); GrAtlasTextBlob::VertexRegenerator::Result result; do { result = regenerator.regenerate(); diff --git a/src/atlastext/SkInternalAtlasTextContext.cpp b/src/atlastext/SkInternalAtlasTextContext.cpp index fcb4130665..1e9cbf3079 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/GrAtlasGlyphCache.h" +#include "text/GrGlyphCache.h" SkAtlasTextRenderer* SkGetAtlasTextRendererFromInternalContext( class SkInternalAtlasTextContext& internal) { @@ -38,17 +38,17 @@ SkInternalAtlasTextContext::SkInternalAtlasTextContext(sk_sp<SkAtlasTextRenderer SkInternalAtlasTextContext::~SkInternalAtlasTextContext() { if (fDistanceFieldAtlas.fProxy) { #ifdef SK_DEBUG - auto atlasGlyphCache = fGrContext->contextPriv().getAtlasGlyphCache(); + auto restrictedAtlasManager = fGrContext->contextPriv().getRestrictedAtlasManager(); unsigned int numProxies; - atlasGlyphCache->getProxies(kA8_GrMaskFormat, &numProxies); + restrictedAtlasManager->getProxies(kA8_GrMaskFormat, &numProxies); SkASSERT(1 == numProxies); #endif fRenderer->deleteTexture(fDistanceFieldAtlas.fTextureHandle); } } -GrAtlasGlyphCache* SkInternalAtlasTextContext::atlasGlyphCache() { - return fGrContext->contextPriv().getAtlasGlyphCache(); +GrGlyphCache* SkInternalAtlasTextContext::glyphCache() { + return fGrContext->contextPriv().getGlyphCache(); } GrTextBlobCache* SkInternalAtlasTextContext::textBlobCache() { @@ -86,11 +86,11 @@ void SkInternalAtlasTextContext::recordDraw(const void* srcVertexData, int glyph } void SkInternalAtlasTextContext::flush() { - auto* atlasGlyphCache = fGrContext->contextPriv().getAtlasGlyphCache(); + auto* restrictedAtlasManager = fGrContext->contextPriv().getRestrictedAtlasManager(); if (!fDistanceFieldAtlas.fProxy) { unsigned int numProxies; - fDistanceFieldAtlas.fProxy = atlasGlyphCache->getProxies(kA8_GrMaskFormat, - &numProxies)->get(); + fDistanceFieldAtlas.fProxy = restrictedAtlasManager->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 cdba3ad8b0..22cda5ca51 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(); } - GrAtlasGlyphCache* atlasGlyphCache(); + GrGlyphCache* glyphCache(); GrTextBlobCache* textBlobCache(); const GrTokenTracker* tokenTracker() final { return &fTokenTracker; } diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 74fbe10ac1..8ccbb2b754 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -77,6 +77,7 @@ public: GrDDLContext(GrContextThreadSafeProxy* proxy) : INHERITED(proxy) {} protected: + // DDL TODO: grab a GrRestrictedAtlasManager from the proxy private: typedef GrContext INHERITED; @@ -218,7 +219,8 @@ GrContext::GrContext(GrBackend backend) fResourceCache = nullptr; fResourceProvider = nullptr; fProxyProvider = nullptr; - fAtlasGlyphCache = nullptr; + fGlyphCache = nullptr; + fFullAtlasManager = nullptr; } GrContext::GrContext(GrContextThreadSafeProxy* proxy) @@ -228,7 +230,8 @@ GrContext::GrContext(GrContextThreadSafeProxy* proxy) fResourceCache = nullptr; fResourceProvider = nullptr; fProxyProvider = nullptr; - fAtlasGlyphCache = nullptr; + fGlyphCache = nullptr; + fFullAtlasManager = nullptr; } bool GrContext::init(const GrContextOptions& options) { @@ -293,9 +296,17 @@ bool GrContext::init(const GrContextOptions& options) { } else { allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes; } - fAtlasGlyphCache = new GrAtlasGlyphCache(fProxyProvider, options.fGlyphCacheTextureMaximumBytes, - allowMultitexturing); - this->contextPriv().addOnFlushCallbackObject(fAtlasGlyphCache); + + 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()); fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this, this->uniqueID(), SkToBool(fGpu))); @@ -327,7 +338,8 @@ GrContext::~GrContext() { delete fResourceProvider; delete fResourceCache; delete fProxyProvider; - delete fAtlasGlyphCache; + delete fGlyphCache; + delete fFullAtlasManager; } sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() { @@ -386,7 +398,8 @@ void GrContext::abandonContext() { fGpu->disconnect(GrGpu::DisconnectType::kAbandon); - fAtlasGlyphCache->freeAll(); + fGlyphCache->freeAll(); + fFullAtlasManager->freeAll(); fTextBlobCache->freeAll(); } @@ -405,7 +418,8 @@ void GrContext::releaseResourcesAndAbandonContext() { fGpu->disconnect(GrGpu::DisconnectType::kCleanup); - fAtlasGlyphCache->freeAll(); + fGlyphCache->freeAll(); + fFullAtlasManager->freeAll(); fTextBlobCache->freeAll(); } @@ -419,7 +433,8 @@ void GrContext::freeGpuResources() { this->flush(); - fAtlasGlyphCache->freeAll(); + fGlyphCache->freeAll(); + fFullAtlasManager->freeAll(); fDrawingManager->freeGpuResources(); diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h index a2a45b5007..c2e525d9b9 100644 --- a/src/gpu/GrContextPriv.h +++ b/src/gpu/GrContextPriv.h @@ -10,6 +10,7 @@ #include "GrContext.h" #include "GrSurfaceContext.h" +#include "text/GrAtlasManager.h" class GrBackendRenderTarget; class GrOnFlushCallbackObject; @@ -187,8 +188,19 @@ public: GrGpu* getGpu() { return fContext->fGpu.get(); } const GrGpu* getGpu() const { return fContext->fGpu.get(); } - GrAtlasGlyphCache* getAtlasGlyphCache() { return fContext->fAtlasGlyphCache; } + GrGlyphCache* getGlyphCache() { return fContext->fGlyphCache; } 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 3fd3110dcc..56dfcef56d 100644 --- a/src/gpu/GrDrawOpAtlas.cpp +++ b/src/gpu/GrDrawOpAtlas.cpp @@ -14,6 +14,7 @@ #include "GrRectanizer.h" #include "GrProxyProvider.h" #include "GrResourceProvider.h" +#include "GrSurfaceProxyPriv.h" #include "GrTexture.h" #include "GrTracing.h" @@ -336,8 +337,8 @@ bool GrDrawOpAtlas::addToAtlas(GrResourceProvider* resourceProvider, // With c+14 we could move sk_sp into lambda to only ref once. sk_sp<Plot> 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 06a05c6bb3..53986c5f6a 100644 --- a/src/gpu/GrOpFlushState.cpp +++ b/src/gpu/GrOpFlushState.cpp @@ -7,6 +7,7 @@ #include "GrOpFlushState.h" +#include "GrContextPriv.h" #include "GrDrawOpAtlas.h" #include "GrGpu.h" #include "GrResourceProvider.h" @@ -191,3 +192,11 @@ 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 1f77c25cb7..ad33a98e2d 100644 --- a/src/gpu/GrOpFlushState.h +++ b/src/gpu/GrOpFlushState.h @@ -90,6 +90,12 @@ 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 dfd06dfe80..254686a613 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,6 +207,7 @@ public: void processInvalidProxyUniqueKey(const GrUniqueKey&, GrTextureProxy*, bool invalidateSurface); const GrCaps* caps() const { return fCaps.get(); } + sk_sp<const GrCaps> refCaps() const { return fCaps; } void abandon() { fResourceCache = nullptr; diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp index 952b3ba5ad..8f0c555295 100644 --- a/src/gpu/ops/GrAtlasTextOp.cpp +++ b/src/gpu/ops/GrAtlasTextOp.cpp @@ -16,7 +16,8 @@ #include "SkPoint3.h" #include "effects/GrBitmapTextGeoProc.h" #include "effects/GrDistanceFieldGeoProc.h" -#include "text/GrAtlasGlyphCache.h" +#include "text/GrAtlasManager.h" +#include "text/GrGlyphCache.h" /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -53,9 +54,12 @@ 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<GrTextureProxy>* proxies = fFontCache->getProxies(this->maskFormat(), - &numProxies); + const sk_sp<GrTextureProxy>* proxies = fRestrictedAtlasManager->getProxies( + this->maskFormat(), &numProxies); for (unsigned int i = 0; i < numProxies; ++i) { if (proxies[i]) { func(proxies[i].get()); @@ -232,10 +236,15 @@ 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<GrTextureProxy>* proxies = fFontCache->getProxies(maskFormat, &atlasPageCount); + const sk_sp<GrTextureProxy>* proxies = fullAtlasManager->getProxies(maskFormat, + &atlasPageCount); if (!proxies[0]) { SkDebugf("Could not allocate backing texture for atlas\n"); return; @@ -246,7 +255,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(); + flushInfo.fGeometryProcessor = this->setupDfProcessor(fullAtlasManager); SkDEBUGCODE(dfPerspective = fGeoData[0].fViewMatrix.hasPerspective()); } else { flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( @@ -272,14 +281,15 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { char* currVertex = reinterpret_cast<char*>(vertices); - SkAutoGlyphCache glyphCache; + SkAutoGlyphCache autoGlyphCache; // 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(), fFontCache, &glyphCache); + args.fColor, target->deferredUploadTarget(), glyphCache, fullAtlasManager, + &autoGlyphCache); GrAtlasTextBlob::VertexRegenerator::Result result; do { result = regenerator.regenerate(); @@ -319,11 +329,14 @@ 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<GrTextureProxy>* proxies = fFontCache->getProxies(maskFormat, &numProxies); + const sk_sp<GrTextureProxy>* proxies = fullAtlasManager->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. @@ -427,9 +440,11 @@ 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<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor() const { +sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor( + GrRestrictedAtlasManager* restrictedAtlasManager) const { unsigned int numProxies; - const sk_sp<GrTextureProxy>* p = fFontCache->getProxies(this->maskFormat(), &numProxies); + const sk_sp<GrTextureProxy>* p = restrictedAtlasManager->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 dbdce387ec..ae1c95b56e 100644 --- a/src/gpu/ops/GrAtlasTextOp.h +++ b/src/gpu/ops/GrAtlasTextOp.h @@ -11,6 +11,7 @@ #include "ops/GrMeshDrawOp.h" #include "text/GrAtlasTextContext.h" #include "text/GrDistanceFieldAdjustTable.h" +#include "text/GrGlyphCache.h" class SkAtlasTextTarget; @@ -39,11 +40,12 @@ public: GrColor fColor; }; - static std::unique_ptr<GrAtlasTextOp> MakeBitmap(GrPaint&& paint, GrMaskFormat maskFormat, - int glyphCount, GrAtlasGlyphCache* fontCache) { - std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp(std::move(paint))); + static std::unique_ptr<GrAtlasTextOp> MakeBitmap( + GrPaint&& paint, GrMaskFormat maskFormat, + int glyphCount, GrRestrictedAtlasManager* restrictedAtlasManager) { + std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp(restrictedAtlasManager, + std::move(paint))); - op->fFontCache = fontCache; switch (maskFormat) { case kA8_GrMaskFormat: op->fMaskType = kGrayscaleCoverageMask_MaskType; @@ -58,18 +60,17 @@ public: op->fNumGlyphs = glyphCount; op->fGeoCount = 1; op->fLuminanceColor = 0; - op->fFontCache = fontCache; return op; } static std::unique_ptr<GrAtlasTextOp> MakeDistanceField( - GrPaint&& paint, int glyphCount, GrAtlasGlyphCache* fontCache, + GrPaint&& paint, int glyphCount, GrRestrictedAtlasManager* restrictedAtlasManager, const GrDistanceFieldAdjustTable* distanceAdjustTable, bool useGammaCorrectDistanceTable, SkColor luminanceColor, bool isLCD, bool useBGR, bool isAntiAliased) { - std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp(std::move(paint))); + std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp(restrictedAtlasManager, + std::move(paint))); - op->fFontCache = fontCache; op->fMaskType = !isAntiAliased ? kAliasedDistanceField_MaskType : isLCD ? (useBGR ? kLCDBGRDistanceField_MaskType : kLCDDistanceField_MaskType) @@ -120,8 +121,9 @@ private: // The minimum number of Geometry we will try to allocate. static constexpr auto kMinGeometryAllocated = 12; - GrAtlasTextOp(GrPaint&& paint) + GrAtlasTextOp(GrRestrictedAtlasManager* restrictedAtlasManager, GrPaint&& paint) : INHERITED(ClassID()) + , fRestrictedAtlasManager(restrictedAtlasManager) , fGeoDataAllocSize(kMinGeometryAllocated) , fSRGBFlags(GrPipeline::SRGBFlagsFromPaint(paint)) , fProcessors(std::move(paint)) {} @@ -174,8 +176,9 @@ private: bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override; - sk_sp<GrGeometryProcessor> setupDfProcessor() const; + sk_sp<GrGeometryProcessor> setupDfProcessor(GrRestrictedAtlasManager*) const; + GrRestrictedAtlasManager* fRestrictedAtlasManager; SkAutoSTMalloc<kMinGeometryAllocated, Geometry> fGeoData; int fGeoDataAllocSize; uint32_t fSRGBFlags; @@ -185,7 +188,6 @@ private: int fGeoCount; int fNumGlyphs; MaskType fMaskType; - GrAtlasGlyphCache* fFontCache; // Distance field properties sk_sp<const GrDistanceFieldAdjustTable> fDistanceAdjustTable; SkColor fLuminanceColor; diff --git a/src/gpu/ops/GrMeshDrawOp.h b/src/gpu/ops/GrMeshDrawOp.h index 1b8831cfe8..766fd23ce5 100644 --- a/src/gpu/ops/GrMeshDrawOp.h +++ b/src/gpu/ops/GrMeshDrawOp.h @@ -15,7 +15,9 @@ #include "SkTLList.h" +class GrAtlasManager; class GrCaps; +class GrGlyphCache; class GrOpFlushState; /** @@ -152,6 +154,9 @@ 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.h b/src/gpu/text/GrAtlasGlyphCache.h deleted file mode 100644 index 84b7d1b249..0000000000 --- a/src/gpu/text/GrAtlasGlyphCache.h +++ /dev/null @@ -1,270 +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 "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<GrAtlasTextStrike> { -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<GrGlyph, GrGlyph::PackedID> 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<GrTextureProxy>* 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<sk_sp<GrRenderTargetContext>>*) 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<GrAtlasTextStrike, SkDescriptor>; - GrProxyProvider* fProxyProvider; - StrikeHash fCache; - GrDrawOpAtlas::AllowMultitexturing fAllowMultitexturing; - std::unique_ptr<GrDrawOpAtlas> fAtlases[kMaskFormatCount]; - GrAtlasTextStrike* fPreserveStrike; - GrDrawOpAtlasConfig fAtlasConfigs[kMaskFormatCount]; - SkScalar fGlyphSizeLimit; -}; - -#endif diff --git a/src/gpu/text/GrAtlasManager.cpp b/src/gpu/text/GrAtlasManager.cpp new file mode 100644 index 0000000000..6e227a94a2 --- /dev/null +++ b/src/gpu/text/GrAtlasManager.cpp @@ -0,0 +1,222 @@ +/* + * 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<const GrCaps> 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 <stdio.h> + +/** + * 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<GrSurfaceContext> 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<GrTextureProxy>* 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 new file mode 100644 index 0000000000..4629cb173b --- /dev/null +++ b/src/gpu/text/GrAtlasManager.h @@ -0,0 +1,155 @@ +/* + * 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<const GrCaps>, 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<GrTextureProxy>* 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<const GrCaps> fCaps; + GrDrawOpAtlas::AllowMultitexturing fAllowMultitexturing; + std::unique_ptr<GrDrawOpAtlas> 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<sk_sp<GrRenderTargetContext>>*) 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 90bcf5a224..35e783019f 100644 --- a/src/gpu/text/GrAtlasTextBlob.cpp +++ b/src/gpu/text/GrAtlasTextBlob.cpp @@ -250,8 +250,8 @@ inline std::unique_ptr<GrAtlasTextOp> 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, GrAtlasGlyphCache* cache, - GrTextUtils::Target* target) { + const GrDistanceFieldAdjustTable* distanceAdjustTable, + GrRestrictedAtlasManager* restrictedAtlasManager, GrTextUtils::Target* target) { GrMaskFormat format = info.maskFormat(); GrPaint grPaint; @@ -260,11 +260,12 @@ inline std::unique_ptr<GrAtlasTextOp> GrAtlasTextBlob::makeOp( if (info.drawAsDistanceFields()) { bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry()); op = GrAtlasTextOp::MakeDistanceField( - std::move(grPaint), glyphCount, cache, distanceAdjustTable, + std::move(grPaint), glyphCount, restrictedAtlasManager, distanceAdjustTable, target->colorSpaceInfo().isGammaCorrect(), paint.luminanceColor(), info.hasUseLCDText(), useBGR, info.isAntiAliased()); } else { - op = GrAtlasTextOp::MakeBitmap(std::move(grPaint), format, glyphCount, cache); + op = GrAtlasTextOp::MakeBitmap(std::move(grPaint), format, + glyphCount, restrictedAtlasManager); } GrAtlasTextOp::Geometry& geometry = op->geometry(); geometry.fViewMatrix = viewMatrix; @@ -300,8 +301,8 @@ static void calculate_translation(bool applyVM, } } -void GrAtlasTextBlob::flush(GrAtlasGlyphCache* atlasGlyphCache, GrTextUtils::Target* target, - const SkSurfaceProps& props, +void GrAtlasTextBlob::flush(GrRestrictedAtlasManager* restrictedAtlasManager, + GrTextUtils::Target* target, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, const GrTextUtils::Paint& paint, const GrClip& clip, const SkMatrix& viewMatrix, const SkIRect& clipBounds, @@ -376,7 +377,7 @@ void GrAtlasTextBlob::flush(GrAtlasGlyphCache* atlasGlyphCache, GrTextUtils::Tar if (submitOp) { auto op = this->makeOp(info, glyphCount, runIndex, subRun, viewMatrix, x, y, clipRect, std::move(paint), props, distanceAdjustTable, - atlasGlyphCache, target); + restrictedAtlasManager, target); if (op) { if (skipClip) { target->addDrawOp(GrNoClip(), std::move(op)); @@ -394,12 +395,12 @@ void GrAtlasTextBlob::flush(GrAtlasGlyphCache* atlasGlyphCache, GrTextUtils::Tar std::unique_ptr<GrDrawOp> 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, GrAtlasGlyphCache* cache, - GrTextUtils::Target* target) { + const GrDistanceFieldAdjustTable* distanceAdjustTable, + GrRestrictedAtlasManager* restrictedAtlasManager, 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, cache, target); + distanceAdjustTable, restrictedAtlasManager, 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 0fae3cd8c7..9f91cae957 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,8 +22,13 @@ #include "SkSurfaceProps.h" #include "SkTInternalLList.h" +class GrAtlasManager; struct GrDistanceFieldAdjustTable; +struct GrGlyph; +class GrGlyphCache; class GrMemoryPool; +class GrRestrictedAtlasManager; + class SkDrawFilter; class SkTextBlob; class SkTextBlobRunIterator; @@ -201,7 +206,7 @@ public: bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilterBase::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y); - void flush(GrAtlasGlyphCache*, GrTextUtils::Target*, const SkSurfaceProps& props, + void flush(GrRestrictedAtlasManager*, GrTextUtils::Target*, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, const GrTextUtils::Paint& paint, const GrClip& clip, const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, @@ -276,8 +281,8 @@ public: std::unique_ptr<GrDrawOp> test_makeOp(int glyphCount, uint16_t run, uint16_t subRun, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const GrTextUtils::Paint&, const SkSurfaceProps&, - const GrDistanceFieldAdjustTable*, GrAtlasGlyphCache*, - GrTextUtils::Target*); + const GrDistanceFieldAdjustTable*, + GrRestrictedAtlasManager*, GrTextUtils::Target*); private: GrAtlasTextBlob() @@ -506,9 +511,8 @@ private: inline std::unique_ptr<GrAtlasTextOp> 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, GrAtlasGlyphCache* cache, - GrTextUtils::Target*); + const GrTextUtils::Paint&, const SkSurfaceProps&, + const GrDistanceFieldAdjustTable*, GrRestrictedAtlasManager* , GrTextUtils::Target*); struct StrokeInfo { SkScalar fFrameWidth; @@ -562,7 +566,8 @@ public: */ VertexRegenerator(GrResourceProvider*, GrAtlasTextBlob*, int runIdx, int subRunIdx, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color, - GrDeferredUploadTarget*, GrAtlasGlyphCache*, SkAutoGlyphCache*); + GrDeferredUploadTarget*, GrGlyphCache*, GrAtlasManager*, + SkAutoGlyphCache*); struct Result { /** @@ -593,7 +598,8 @@ private: const SkMatrix& fViewMatrix; GrAtlasTextBlob* fBlob; GrDeferredUploadTarget* fUploadTarget; - GrAtlasGlyphCache* fGlyphCache; + GrGlyphCache* fGlyphCache; + GrAtlasManager* fFullAtlasManager; SkAutoGlyphCache* fLazyCache; Run* fRun; Run::SubRunInfo* fSubRun; diff --git a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp index 500ae31703..54001c2628 100644 --- a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp +++ b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "GrAtlasManager.h" #include "GrAtlasTextBlob.h" #include "GrTextUtils.h" #include "SkDistanceFieldGen.h" @@ -193,13 +194,14 @@ 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, GrAtlasGlyphCache* glyphCache, - SkAutoGlyphCache* lazyCache) + GrDeferredUploadTarget* uploadTarget, GrGlyphCache* glyphCache, + GrAtlasManager* fullAtlasManager, 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]) @@ -207,7 +209,7 @@ Regenerator::VertexRegenerator(GrResourceProvider* resourceProvider, GrAtlasText // Compute translation if any fSubRun->computeTranslation(fViewMatrix, x, y, &fTransX, &fTransY); - // Because the GrAtlasGlyphCache may evict the strike a blob depends on using for + // Because the GrGlyphCache 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. @@ -275,16 +277,17 @@ Regenerator::Result Regenerator::doRegen() { glyph = fBlob->fGlyphs[glyphOffset]; SkASSERT(glyph && glyph->fMaskFormat == fSubRun->maskFormat()); - if (!fGlyphCache->hasGlyph(glyph) && - !strike->addGlyphToAtlas(fResourceProvider, fUploadTarget, fGlyphCache, glyph, + if (!fFullAtlasManager->hasGlyph(glyph) && + !strike->addGlyphToAtlas(fResourceProvider, fUploadTarget, fGlyphCache, + fFullAtlasManager, glyph, fLazyCache->get(), fSubRun->maskFormat())) { fBrokenRun = glyphIdx > 0; result.fFinished = false; return result; } auto tokenTracker = fUploadTarget->tokenTracker(); - fGlyphCache->addGlyphToBulkAndSetUseToken(fSubRun->bulkUseToken(), glyph, - tokenTracker->nextDrawToken()); + fFullAtlasManager->addGlyphToBulkAndSetUseToken(fSubRun->bulkUseToken(), glyph, + tokenTracker->nextDrawToken()); } regen_vertices<regenPos, regenCol, regenTexCoords>(currVertex, glyph, vertexStride, @@ -302,14 +305,14 @@ Regenerator::Result Regenerator::doRegen() { fSubRun->setStrike(strike); } fSubRun->setAtlasGeneration(fBrokenRun - ? GrDrawOpAtlas::kInvalidAtlasGeneration - : fGlyphCache->atlasGeneration(fSubRun->maskFormat())); + ? GrDrawOpAtlas::kInvalidAtlasGeneration + : fFullAtlasManager->atlasGeneration(fSubRun->maskFormat())); } return result; } Regenerator::Result Regenerator::regenerate() { - uint64_t currentAtlasGen = fGlyphCache->atlasGeneration(fSubRun->maskFormat()); + uint64_t currentAtlasGen = fFullAtlasManager->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) { @@ -352,9 +355,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 - fGlyphCache->setUseTokenBulk(*fSubRun->bulkUseToken(), - fUploadTarget->tokenTracker()->nextDrawToken(), - fSubRun->maskFormat()); + fFullAtlasManager->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 06282e103e..aadc2dc0c1 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -118,7 +118,8 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t drawFilter); SkScalerContextFlags scalerContextFlags = ComputeScalerContextFlags(target->colorSpaceInfo()); - auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache(); + auto glyphCache = context->contextPriv().getGlyphCache(); + auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager(); GrTextBlobCache* textBlobCache = context->contextPriv().getTextBlobCache(); if (canCache) { @@ -151,7 +152,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(), atlasGlyphCache, + this->regenerateTextBlob(cacheBlob.get(), glyphCache, *context->caps()->shaderCaps(), paint, scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter); } else { @@ -163,7 +164,7 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob); sk_sp<GrAtlasTextBlob> sanityBlob(textBlobCache->makeBlob(glyphCount, runCount)); sanityBlob->setupKey(key, blurRec, skPaint); - this->regenerateTextBlob(sanityBlob.get(), atlasGlyphCache, + this->regenerateTextBlob(sanityBlob.get(), glyphCache, *context->caps()->shaderCaps(), paint, scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter); GrAtlasTextBlob::AssertEqual(*sanityBlob, *cacheBlob); @@ -175,17 +176,17 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t } else { cacheBlob = textBlobCache->makeBlob(blob); } - this->regenerateTextBlob(cacheBlob.get(), atlasGlyphCache, + this->regenerateTextBlob(cacheBlob.get(), glyphCache, *context->caps()->shaderCaps(), paint, scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter); } - cacheBlob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, + cacheBlob->flush(restrictedAtlasManager, target, props, fDistanceAdjustTable.get(), paint, clip, viewMatrix, clipBounds, x, y); } void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, - GrAtlasGlyphCache* fontCache, + GrGlyphCache* glyphCache, const GrShaderCaps& shaderCaps, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, @@ -211,21 +212,21 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, if (this->canDrawAsDistanceFields(runPaint, viewMatrix, props, shaderCaps)) { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: { - this->drawDFText(cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, + this->drawDFText(cacheBlob, run, glyphCache, 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, fontCache, props, runPaint, + this->drawDFPosText(cacheBlob, run, glyphCache, 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, fontCache, props, runPaint, + this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2, dfOffset); break; @@ -234,17 +235,17 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, } else { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: - DrawBmpText(cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, + DrawBmpText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, viewMatrix, (const char*)it.glyphs(), textLen, x + offset.x(), y + offset.y()); break; case SkTextBlob::kHorizontal_Positioning: - DrawBmpPosText(cacheBlob, run, fontCache, props, runPaint, scalerContextFlags, + DrawBmpPosText(cacheBlob, run, glyphCache, 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, fontCache, props, runPaint, scalerContextFlags, + DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2, SkPoint::Make(x, y)); break; @@ -255,7 +256,7 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, inline sk_sp<GrAtlasTextBlob> GrAtlasTextContext::makeDrawTextBlob(GrTextBlobCache* blobCache, - GrAtlasGlyphCache* fontCache, + GrGlyphCache* glyphCache, const GrShaderCaps& shaderCaps, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, @@ -272,10 +273,10 @@ GrAtlasTextContext::makeDrawTextBlob(GrTextBlobCache* blobCache, blob->setRunPaintFlags(0, paint.skPaint().getFlags()); if (this->canDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) { - this->drawDFText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix, + this->drawDFText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, x, y); } else { - DrawBmpText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix, text, + DrawBmpText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, x, y); } return blob; @@ -283,7 +284,7 @@ GrAtlasTextContext::makeDrawTextBlob(GrTextBlobCache* blobCache, inline sk_sp<GrAtlasTextBlob> GrAtlasTextContext::makeDrawPosTextBlob(GrTextBlobCache* blobCache, - GrAtlasGlyphCache* fontCache, + GrGlyphCache* glyphCache, const GrShaderCaps& shaderCaps, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, @@ -302,11 +303,11 @@ GrAtlasTextContext::makeDrawPosTextBlob(GrTextBlobCache* blobCache, blob->setRunPaintFlags(0, paint.skPaint().getFlags()); if (this->canDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) { - this->drawDFPosText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix, + this->drawDFPosText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset); } else { - DrawBmpPosText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix, text, - byteLength, pos, scalarsPerPosition, offset); + DrawBmpPosText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, + text, byteLength, pos, scalarsPerPosition, offset); } return blob; } @@ -320,17 +321,18 @@ void GrAtlasTextContext::drawText(GrContext* context, GrTextUtils::Target* targe return; } - auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache(); + auto glyphCache = context->contextPriv().getGlyphCache(); + auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager(); auto textBlobCache = context->contextPriv().getTextBlobCache(); GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo()); sk_sp<GrAtlasTextBlob> blob( - this->makeDrawTextBlob(textBlobCache, atlasGlyphCache, + this->makeDrawTextBlob(textBlobCache, glyphCache, *context->caps()->shaderCaps(), paint, ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text, byteLength, x, y)); if (blob) { - blob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, + blob->flush(restrictedAtlasManager, target, props, fDistanceAdjustTable.get(), paint, clip, viewMatrix, regionClipBounds, x, y); } } @@ -346,22 +348,23 @@ void GrAtlasTextContext::drawPosText(GrContext* context, GrTextUtils::Target* ta return; } - auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache(); + auto glyphCache = context->contextPriv().getGlyphCache(); + auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager(); auto textBlobCache = context->contextPriv().getTextBlobCache(); sk_sp<GrAtlasTextBlob> blob(this->makeDrawPosTextBlob( - textBlobCache, atlasGlyphCache, + textBlobCache, glyphCache, *context->caps()->shaderCaps(), paint, ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text, byteLength, pos, scalarsPerPosition, offset)); if (blob) { - blob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, + blob->flush(restrictedAtlasManager, target, props, fDistanceAdjustTable.get(), paint, clip, viewMatrix, regionClipBounds, offset.fX, offset.fY); } } void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, - GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, + GrGlyphCache* glyphCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], @@ -377,7 +380,7 @@ void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, blob->setHasBitmap(); if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) { - DrawBmpTextAsPaths(blob, runIndex, fontCache, props, paint, scalerContextFlags, viewMatrix, + DrawBmpTextAsPaths(blob, runIndex, glyphCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, x, y); return; } @@ -387,7 +390,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, fontCache, &currStrike, + BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, SkScalarFloorToScalar(position.fX), SkScalarFloorToScalar(position.fY), paint.filteredPremulColor(), cache, @@ -398,7 +401,7 @@ void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, } void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, - GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, + GrGlyphCache* glyphCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, @@ -416,7 +419,7 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, blob->setHasBitmap(); if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) { - DrawBmpPosTextAsPaths(blob, runIndex, fontCache, props, paint, scalerContextFlags, + DrawBmpPosTextAsPaths(blob, runIndex, glyphCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset); return; } @@ -429,7 +432,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, fontCache, &currStrike, glyph, + BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, SkScalarFloorToScalar(position.fX), SkScalarFloorToScalar(position.fY), paint.filteredPremulColor(), cache, SK_Scalar1); @@ -439,7 +442,7 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, } void GrAtlasTextContext::DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex, - GrAtlasGlyphCache* fontCache, + GrGlyphCache* glyphCache, const SkSurfaceProps& props, const GrTextUtils::Paint& origPaint, SkScalerContextFlags scalerContextFlags, @@ -457,7 +460,7 @@ void GrAtlasTextContext::DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex, GrTextUtils::PathTextIter iter(text, byteLength, pathPaint, true); FallbackTextHelper fallbackTextHelper(viewMatrix, pathPaint.getTextSize(), - fontCache->getGlyphSizeLimit(), + glyphCache->getGlyphSizeLimit(), iter.getPathScale()); const SkGlyph* iterGlyph; @@ -474,11 +477,11 @@ void GrAtlasTextContext::DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex, lastText = iter.getText(); } - fallbackTextHelper.drawText(blob, runIndex, fontCache, props, origPaint, scalerContextFlags); + fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, origPaint, scalerContextFlags); } void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runIndex, - GrAtlasGlyphCache* fontCache, + GrGlyphCache* glyphCache, const SkSurfaceProps& props, const GrTextUtils::Paint& origPaint, SkScalerContextFlags scalerContextFlags, @@ -497,7 +500,7 @@ void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runInd SkPaint pathPaint(origPaint); SkScalar matrixScale = pathPaint.setupForAsPaths(); FallbackTextHelper fallbackTextHelper(viewMatrix, pathPaint.getTextSize(), matrixScale, - fontCache->getGlyphSizeLimit()); + glyphCache->getGlyphSizeLimit()); // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. pathPaint.setStyle(SkPaint::kFill_Style); @@ -534,23 +537,23 @@ void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runInd pos += scalarsPerPosition; } - fallbackTextHelper.drawText(blob, runIndex, fontCache, props, origPaint, scalerContextFlags); + fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, origPaint, scalerContextFlags); } void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, - GrAtlasGlyphCache* fontCache, GrAtlasTextStrike** strike, + GrGlyphCache* grGlyphCache, GrAtlasTextStrike** strike, const SkGlyph& skGlyph, SkScalar sx, SkScalar sy, - GrColor color, SkGlyphCache* glyphCache, + GrColor color, SkGlyphCache* skGlyphCache, SkScalar textRatio) { if (!*strike) { - *strike = fontCache->getStrike(glyphCache); + *strike = grGlyphCache->getStrike(skGlyphCache); } GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), skGlyph.getSubXFixed(), skGlyph.getSubYFixed(), GrGlyph::kCoverage_MaskStyle); - GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, glyphCache); + GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, skGlyphCache); if (!glyph) { return; } @@ -570,7 +573,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, glyphCache, skGlyph, sx, sy, + blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, skGlyphCache, skGlyph, sx, sy, textRatio, true); } @@ -670,7 +673,7 @@ void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob, } void GrAtlasTextContext::drawDFText(GrAtlasTextBlob* blob, int runIndex, - GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, + GrGlyphCache* glyphCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], @@ -740,12 +743,12 @@ void GrAtlasTextContext::drawDFText(GrAtlasTextBlob* blob, int runIndex, y -= alignY; SkPoint offset = SkPoint::Make(x, y); - this->drawDFPosText(blob, runIndex, fontCache, props, paint, scalerContextFlags, viewMatrix, + this->drawDFPosText(blob, runIndex, glyphCache, props, paint, scalerContextFlags, viewMatrix, text, byteLength, positions.begin(), 2, offset); } void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, - GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, + GrGlyphCache* glyphCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], @@ -771,7 +774,7 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, FallbackTextHelper fallbackTextHelper(viewMatrix, paint.skPaint().getTextSize(), - fontCache->getGlyphSizeLimit(), + glyphCache->getGlyphSizeLimit(), textRatio); GrAtlasTextStrike* currStrike = nullptr; @@ -800,7 +803,7 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkFloatToScalar(glyph.fAdvanceY) * alignMul * textRatio; if (glyph.fMaskFormat != SkMask::kARGB32_Format) { - DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, glyphPos.fX, + DfAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, glyphPos.fX, glyphPos.fY, paint.filteredPremulColor(), cache, textRatio); } else { // can't append color glyph to SDF batch, send to fallback @@ -812,25 +815,24 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkGlyphCache::AttachCache(cache); - fallbackTextHelper.drawText(blob, runIndex, fontCache, props, paint, - scalerContextFlags); + fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, paint, scalerContextFlags); } // TODO: merge with BmpAppendGlyph void GrAtlasTextContext::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, - GrAtlasGlyphCache* cache, GrAtlasTextStrike** strike, + GrGlyphCache* grGlyphCache, GrAtlasTextStrike** strike, const SkGlyph& skGlyph, SkScalar sx, SkScalar sy, - GrColor color, SkGlyphCache* glyphCache, + GrColor color, SkGlyphCache* skGlyphCache, SkScalar textRatio) { if (!*strike) { - *strike = cache->getStrike(glyphCache); + *strike = grGlyphCache->getStrike(skGlyphCache); } GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), skGlyph.getSubXFixed(), skGlyph.getSubYFixed(), GrGlyph::kDistance_MaskStyle); - GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, glyphCache); + GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, skGlyphCache); if (!glyph) { return; } @@ -846,7 +848,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, glyphCache, skGlyph, sx, sy, + blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, skGlyphCache, skGlyph, sx, sy, textRatio, false); } @@ -871,7 +873,7 @@ void GrAtlasTextContext::FallbackTextHelper::appendText(const SkGlyph& glyph, in } void GrAtlasTextContext::FallbackTextHelper::drawText(GrAtlasTextBlob* blob, int runIndex, - GrAtlasGlyphCache* fontCache, + GrGlyphCache* glyphCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags) { @@ -909,7 +911,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, fontCache, &currStrike, glyph, + GrAtlasTextContext::BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, glyphPos->fX, glyphPos->fY, textColor, cache, textRatio); glyphPos++; @@ -962,18 +964,19 @@ GR_DRAW_OP_TEST_DEFINE(GrAtlasTextOp) { SkScalar x = SkIntToScalar(xInt); SkScalar y = SkIntToScalar(yInt); - auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache(); + auto glyphCache = context->contextPriv().getGlyphCache(); + auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager(); // 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<GrAtlasTextBlob> blob(gTextContext->makeDrawTextBlob( - context->contextPriv().getTextBlobCache(), atlasGlyphCache, + context->contextPriv().getTextBlobCache(), glyphCache, *context->caps()->shaderCaps(), utilsPaint, GrAtlasTextContext::kTextBlobOpScalerContextFlags, viewMatrix, gSurfaceProps, text, static_cast<size_t>(textLen), x, y)); return blob->test_makeOp(textLen, 0, 0, viewMatrix, x, y, utilsPaint, gSurfaceProps, - gTextContext->dfAdjustTable(), atlasGlyphCache, + gTextContext->dfAdjustTable(), restrictedAtlasManager, rtc->textTarget()); } diff --git a/src/gpu/text/GrAtlasTextContext.h b/src/gpu/text/GrAtlasTextContext.h index 207dd67206..37b7de5357 100644 --- a/src/gpu/text/GrAtlasTextContext.h +++ b/src/gpu/text/GrAtlasTextContext.h @@ -74,9 +74,8 @@ private: } void appendText(const SkGlyph& glyph, int count, const char* text, SkPoint glyphPos); - void drawText(GrAtlasTextBlob* blob, int runIndex, - GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props, - const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags); + void drawText(GrAtlasTextBlob* blob, int runIndex, GrGlyphCache*, const SkSurfaceProps&, + const GrTextUtils::Paint&, SkScalerContextFlags); private: SkTDArray<char> fFallbackTxt; @@ -96,7 +95,7 @@ private: // Determines if we need to use fake gamma (and contrast boost): static SkScalerContextFlags ComputeScalerContextFlags(const GrColorSpaceInfo&); void regenerateTextBlob(GrAtlasTextBlob* bmp, - GrAtlasGlyphCache*, + GrGlyphCache*, const GrShaderCaps&, const GrTextUtils::Paint&, SkScalerContextFlags scalerContextFlags, @@ -107,7 +106,7 @@ private: static bool HasLCD(const SkTextBlob*); - sk_sp<GrAtlasTextBlob> makeDrawTextBlob(GrTextBlobCache*, GrAtlasGlyphCache*, + sk_sp<GrAtlasTextBlob> makeDrawTextBlob(GrTextBlobCache*, GrGlyphCache*, const GrShaderCaps&, const GrTextUtils::Paint&, SkScalerContextFlags scalerContextFlags, @@ -116,7 +115,7 @@ private: const char text[], size_t byteLength, SkScalar x, SkScalar y) const; - sk_sp<GrAtlasTextBlob> makeDrawPosTextBlob(GrTextBlobCache*, GrAtlasGlyphCache*, + sk_sp<GrAtlasTextBlob> makeDrawPosTextBlob(GrTextBlobCache*, GrGlyphCache*, const GrShaderCaps&, const GrTextUtils::Paint&, SkScalerContextFlags scalerContextFlags, @@ -128,24 +127,24 @@ private: const SkPoint& offset) const; // Functions for appending BMP text to GrAtlasTextBlob - static void DrawBmpText(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, + static void DrawBmpText(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, 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, GrAtlasGlyphCache*, + static void DrawBmpPosText(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, 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, GrAtlasGlyphCache*, + static void DrawBmpTextAsPaths(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, 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, GrAtlasGlyphCache*, + static void DrawBmpPosTextAsPaths(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, @@ -157,12 +156,12 @@ private: bool canDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const GrShaderCaps& caps) const; - void drawDFText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache*, const SkSurfaceProps&, + void drawDFText(GrAtlasTextBlob* blob, int runIndex, GrGlyphCache*, 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, GrAtlasGlyphCache*, + void drawDFPosText(GrAtlasTextBlob* blob, int runIndex, GrGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], @@ -174,11 +173,11 @@ private: SkScalar* textRatio, const SkMatrix& viewMatrix) const; - static void BmpAppendGlyph(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, + static void BmpAppendGlyph(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, GrAtlasTextStrike**, const SkGlyph&, SkScalar sx, SkScalar sy, GrColor color, SkGlyphCache*, SkScalar textRatio); - static void DfAppendGlyph(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, + static void DfAppendGlyph(GrAtlasTextBlob*, int runIndex, GrGlyphCache*, GrAtlasTextStrike**, const SkGlyph&, SkScalar sx, SkScalar sy, GrColor color, SkGlyphCache* cache, SkScalar textRatio); diff --git a/src/gpu/text/GrAtlasGlyphCache.cpp b/src/gpu/text/GrGlyphCache.cpp index f7b1e1269a..d4440897bc 100644 --- a/src/gpu/text/GrAtlasGlyphCache.cpp +++ b/src/gpu/text/GrGlyphCache.cpp @@ -5,81 +5,19 @@ * found in the LICENSE file. */ -#include "GrAtlasGlyphCache.h" -#include "GrContext.h" +#include "GrAtlasManager.h" #include "GrDistanceFieldGenFromVector.h" -#include "GrGpu.h" -#include "GrProxyProvider.h" -#include "GrRectanizer.h" +#include "GrGlyphCache.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; +GrGlyphCache::GrGlyphCache() + : fPreserveStrike(nullptr) + , fGlyphSizeLimit(0) { } -GrAtlasGlyphCache::~GrAtlasGlyphCache() { +GrGlyphCache::~GrGlyphCache() { StrikeHash::Iter iter(&fCache); while (!iter.done()) { (*iter).fIsAbandoned = true; @@ -88,7 +26,7 @@ GrAtlasGlyphCache::~GrAtlasGlyphCache() { } } -void GrAtlasGlyphCache::freeAll() { +void GrGlyphCache::freeAll() { StrikeHash::Iter iter(&fCache); while (!iter.done()) { (*iter).fIsAbandoned = true; @@ -96,120 +34,26 @@ void GrAtlasGlyphCache::freeAll() { ++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<GrAtlasGlyphCache*>(ptr); +void GrGlyphCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) { + GrGlyphCache* glyphCache = reinterpret_cast<GrGlyphCache*>(ptr); - StrikeHash::Iter iter(&fontCache->fCache); + 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 != fontCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) { - fontCache->fCache.remove(GrAtlasTextStrike::GetKey(*strike)); + if (strike != glyphCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) { + glyphCache->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 <stdio.h> - -/** - * 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<GrSurfaceContext> 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<GrTextureProxy>* 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<SkMask::Format>(glyph.fMaskFormat); switch (format) { @@ -450,7 +294,8 @@ void GrAtlasTextStrike::removeID(GrDrawOpAtlas::AtlasID id) { bool GrAtlasTextStrike::addGlyphToAtlas(GrResourceProvider* resourceProvider, GrDeferredUploadTarget* target, - GrAtlasGlyphCache* atlasGlyphCache, + GrGlyphCache* glyphCache, + GrAtlasManager* fullAtlasManager, GrGlyph* glyph, SkGlyphCache* cache, GrMaskFormat expectedMaskFormat) { @@ -477,10 +322,10 @@ bool GrAtlasTextStrike::addGlyphToAtlas(GrResourceProvider* resourceProvider, } } - bool success = atlasGlyphCache->addToAtlas(resourceProvider, this, &glyph->fID, target, - expectedMaskFormat, - glyph->width(), glyph->height(), - storage.get(), &glyph->fAtlasLocation); + 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++; diff --git a/src/gpu/text/GrGlyphCache.h b/src/gpu/text/GrGlyphCache.h new file mode 100644 index 0000000000..169e4b30a5 --- /dev/null +++ b/src/gpu/text/GrGlyphCache.h @@ -0,0 +1,148 @@ +/* + * 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<GrAtlasTextStrike> { +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<GrGlyph, GrGlyph::PackedID> 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<GrAtlasTextStrike, SkDescriptor>; + + StrikeHash fCache; + GrAtlasTextStrike* fPreserveStrike; + SkScalar fGlyphSizeLimit; +}; + +#endif diff --git a/src/gpu/text/GrTextUtils.h b/src/gpu/text/GrTextUtils.h index 5fe38fe773..69421c2474 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 a34618e38f..7e35a07726 100644 --- a/tests/DrawOpAtlasTest.cpp +++ b/tests/DrawOpAtlasTest.cpp @@ -11,7 +11,7 @@ #include "GrContextPriv.h" #include "Test.h" -#include "text/GrAtlasGlyphCache.h" +#include "text/GrGlyphCache.h" static const int kNumPlots = 2; static const int kPlotSize = 32; diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp index c6d3bbe2ef..c483a22aac 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/GrAtlasGlyphCache.h" +#include "text/GrGlyphCache.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) { - fAtlasGlyphCache->setAtlasSizes_ForTesting(configs); + fFullAtlasManager->setAtlasSizes_ForTesting(configs); } /////////////////////////////////////////////////////////////////////////////// @@ -147,11 +147,11 @@ void GrContext::printGpuStats() const { SkDebugf("%s", out.c_str()); } -sk_sp<SkImage> GrContext::getFontAtlasImage_ForTesting(GrMaskFormat format, uint32_t index) { - GrAtlasGlyphCache* cache = this->contextPriv().getAtlasGlyphCache(); +sk_sp<SkImage> GrContext::getFontAtlasImage_ForTesting(GrMaskFormat format, unsigned int index) { + auto restrictedAtlasManager = this->contextPriv().getRestrictedAtlasManager(); unsigned int numProxies; - const sk_sp<GrTextureProxy>* proxies = cache->getProxies(format, &numProxies); + const sk_sp<GrTextureProxy>* proxies = restrictedAtlasManager->getProxies(format, &numProxies); if (index >= numProxies || !proxies[index]) { return nullptr; } |