Fission GrAtlasGlyphCache in two (take 2)

Reland all the things

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.

TBR=jvanverth@google.com
Change-Id: I05c6cd8d301bf2decca39765e5cae62993d9da04
Reviewed-on: https://skia-review.googlesource.com/111362
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2018-03-01 11:36:45 -05:00 committed by Skia Commit-Bot
parent 2d0e1248d6
commit c4039ea466
27 changed files with 788 additions and 609 deletions

View File

@ -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",

View File

@ -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;

View File

@ -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();

View File

@ -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,

View File

@ -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; }

View File

@ -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();

View File

@ -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);

View File

@ -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) {

View File

@ -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();
}

View File

@ -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; }

View File

@ -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;

View File

@ -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>* proxies = fFontCache->getProxies(this->maskFormat(), &numProxies);
const sk_sp<GrTextureProxy>* proxies = restrictedAtlasManager->getProxies(this->maskFormat(),
&numProxies);
bool isLCD = this->isLCD();
SkMatrix localMatrix = SkMatrix::I();

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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());
}

View File

@ -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);

View File

@ -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;
GrGlyphCache::GrGlyphCache()
: fPreserveStrike(nullptr)
, fGlyphSizeLimit(0) {
}
GrAtlasGlyphCache::GrAtlasGlyphCache(GrProxyProvider* proxyProvider, float maxTextureBytes,
GrDrawOpAtlas::AllowMultitexturing allowMultitexturing)
: fProxyProvider(proxyProvider)
, fAllowMultitexturing(allowMultitexturing)
, fPreserveStrike(nullptr) {
// Calculate RGBA size. Must be between 512 x 256 and MaxTextureSize x MaxTextureSize / 2
int log2MaxTextureSize = SkPrevLog2(fProxyProvider->caps()->maxTextureSize());
int log2MaxDim = 9;
for (; log2MaxDim <= log2MaxTextureSize; ++log2MaxDim) {
int maxDim = 1 << log2MaxDim;
int minDim = 1 << (log2MaxDim - 1);
if (maxDim * minDim * 4 >= maxTextureBytes) break;
}
int log2MinDim = log2MaxDim - 1;
int maxDim = 1 << log2MaxDim;
int minDim = 1 << log2MinDim;
// Plots are either 256 or 512.
int maxPlot = SkTMin(512, SkTMax(256, 1 << (log2MaxDim - 2)));
int minPlot = SkTMin(512, SkTMax(256, 1 << (log2MaxDim - 3)));
// Setup default atlas configs. The A8 atlas uses maxDim for both width and height, as the A8
// format is already very compact.
fAtlasConfigs[kA8_GrMaskFormat].fWidth = maxDim;
fAtlasConfigs[kA8_GrMaskFormat].fHeight = maxDim;
fAtlasConfigs[kA8_GrMaskFormat].fPlotWidth = maxPlot;
fAtlasConfigs[kA8_GrMaskFormat].fPlotHeight = minPlot;
// A565 and ARGB use maxDim x minDim.
fAtlasConfigs[kA565_GrMaskFormat].fWidth = minDim;
fAtlasConfigs[kA565_GrMaskFormat].fHeight = maxDim;
fAtlasConfigs[kA565_GrMaskFormat].fPlotWidth = minPlot;
fAtlasConfigs[kA565_GrMaskFormat].fPlotHeight = minPlot;
fAtlasConfigs[kARGB_GrMaskFormat].fWidth = minDim;
fAtlasConfigs[kARGB_GrMaskFormat].fHeight = maxDim;
fAtlasConfigs[kARGB_GrMaskFormat].fPlotWidth = minPlot;
fAtlasConfigs[kARGB_GrMaskFormat].fPlotHeight = minPlot;
fGlyphSizeLimit = minPlot;
}
GrAtlasGlyphCache::~GrAtlasGlyphCache() {
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++;

148
src/gpu/text/GrGlyphCache.h Normal file
View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;
}