aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/text
diff options
context:
space:
mode:
authorGravatar Robert Phillips <robertphillips@google.com>2018-02-27 16:43:18 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-02-27 22:05:55 +0000
commitacf17904d6286f2a63a5d895541804d0ea1be646 (patch)
treeefafdb48995fd150c37b1442bf58295d4d66cd89 /src/gpu/text
parentc420525bd4cde4cdac471880d080d8c742307788 (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>
Diffstat (limited to 'src/gpu/text')
-rw-r--r--src/gpu/text/GrAtlasGlyphCache.h270
-rw-r--r--src/gpu/text/GrAtlasManager.cpp222
-rw-r--r--src/gpu/text/GrAtlasManager.h155
-rw-r--r--src/gpu/text/GrAtlasTextBlob.cpp21
-rw-r--r--src/gpu/text/GrAtlasTextBlob.h24
-rw-r--r--src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp29
-rw-r--r--src/gpu/text/GrAtlasTextContext.cpp121
-rw-r--r--src/gpu/text/GrAtlasTextContext.h27
-rw-r--r--src/gpu/text/GrGlyphCache.cpp (renamed from src/gpu/text/GrAtlasGlyphCache.cpp)191
-rw-r--r--src/gpu/text/GrGlyphCache.h148
-rw-r--r--src/gpu/text/GrTextUtils.h2
11 files changed, 661 insertions, 549 deletions
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;