aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/gpu/GrContextOptions.h2
-rw-r--r--src/core/SkRemoteGlyphCache.cpp185
-rw-r--r--src/core/SkRemoteGlyphCache.h25
-rw-r--r--src/core/SkTypeface_remote.cpp10
-rw-r--r--src/gpu/text/GrAtlasManager.cpp14
-rw-r--r--src/gpu/text/GrAtlasManager.h4
-rw-r--r--src/gpu/text/GrGlyphCache.cpp20
-rw-r--r--src/gpu/text/GrGlyphCache.h3
-rw-r--r--src/gpu/text/GrTextContext.cpp33
-rw-r--r--src/gpu/text/GrTextContext.h23
-rw-r--r--tests/SkRemoteGlyphCacheTest.cpp13
11 files changed, 232 insertions, 100 deletions
diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h
index 2d3151db67..11838707b5 100644
--- a/include/gpu/GrContextOptions.h
+++ b/include/gpu/GrContextOptions.h
@@ -98,7 +98,7 @@ struct GrContextOptions {
/**
* The maximum size of cache textures used for Skia's Glyph cache.
*/
- float fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4;
+ size_t fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4;
/**
* Below this threshold size in device space distance field fonts won't be used. Distance field
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp
index 922014b173..fe3b900fe6 100644
--- a/src/core/SkRemoteGlyphCache.cpp
+++ b/src/core/SkRemoteGlyphCache.cpp
@@ -168,6 +168,49 @@ bool read_path(Deserializer* deserializer, SkGlyph* glyph, SkGlyphCache* cache)
return cache->initializePath(glyph, path, pathSize);
}
+#if SK_SUPPORT_GPU
+SkScalar glyph_size_limit(const SkTextBlobCacheDiffCanvas::Settings& settings) {
+ return GrGlyphCache::ComputeGlyphSizeLimit(settings.fMaxTextureSize, settings.fMaxTextureBytes);
+}
+
+void add_glyph_to_cache(SkStrikeServer::SkGlyphCacheState* cache, SkTypeface* tf,
+ const SkScalerContextEffects& effects, const char** text) {
+ SkASSERT(cache != nullptr);
+ SkASSERT(text != nullptr);
+
+ const uint16_t* ptr = *(const uint16_t**)text;
+ unsigned glyphID = *ptr;
+ ptr += 1;
+ *text = (const char*)ptr;
+ cache->addGlyph(tf, effects, SkPackedGlyphID(glyphID, 0, 0), false);
+}
+
+void add_fallback_text_to_cache(const GrTextContext::FallbackTextHelper& helper,
+ const SkSurfaceProps& props,
+ const SkMatrix& matrix,
+ const SkPaint& origPaint,
+ SkStrikeServer* server) {
+ if (!helper.fallbackText().count()) return;
+
+ SkPaint fallbackPaint{origPaint};
+ SkScalar textRatio;
+ SkMatrix fallbackMatrix = matrix;
+ helper.initializeForDraw(&fallbackPaint, &textRatio, &fallbackMatrix);
+
+ SkScalerContextRec deviceSpecificRec;
+ SkScalerContextEffects effects;
+ auto* glyphCacheState = server->getOrCreateCache(
+ fallbackPaint, &props, &fallbackMatrix,
+ SkScalerContextFlags::kFakeGammaAndBoostContrast, &deviceSpecificRec, &effects);
+
+ const char* text = helper.fallbackText().begin();
+ const char* stop = text + helper.fallbackText().count();
+ while (text < stop) {
+ add_glyph_to_cache(glyphCacheState, fallbackPaint.getTypeface(), effects, &text);
+ }
+}
+#endif
+
size_t SkDescriptorMapOperators::operator()(const SkDescriptor* key) const {
return key->getChecksum();
}
@@ -277,26 +320,14 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun(
runMatrix.preConcat(this->getTotalMatrix());
#if SK_SUPPORT_GPU
- GrTextContext::Options options;
- options.fMinDistanceFieldFontSize = fSettings.fMinDistanceFieldFontSize;
- options.fMaxDistanceFieldFontSize = fSettings.fMaxDistanceFieldFontSize;
- GrTextContext::SanitizeOptions(&options);
- if (GrTextContext::CanDrawAsDistanceFields(runPaint, runMatrix, this->surfaceProps(),
- fSettings.fContextSupportsDistanceFieldText,
- options)) {
- SkScalar textRatio;
- SkPaint dfPaint(runPaint);
- SkScalerContextFlags flags;
- GrTextContext::InitDistanceFieldPaint(nullptr, &dfPaint, runMatrix, options,
- &textRatio, &flags);
- this->processGlyphRunForDFT(it, dfPaint, flags);
+ if (this->processGlyphRunForDFT(it, runPaint, runMatrix)) {
+ return;
}
#endif
// If the matrix has perspective, we fall back to using distance field text or paths.
- // TODO: Add distance field text support, and FallbackTextHelper logic from GrTextContext.
if (SkDraw::ShouldDrawTextAsPaths(runPaint, runMatrix)) {
- this->processGlyphRunForPaths(it, runPaint);
+ this->processGlyphRunForPaths(it, runPaint, runMatrix);
return;
}
@@ -326,11 +357,9 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun(
SkScalerContextRec deviceSpecificRec;
SkScalerContextEffects effects;
- auto* glyphCacheState =
- static_cast<SkStrikeServer*>(fStrikeServer)
- ->getOrCreateCache(runPaint, &this->surfaceProps(), &runMatrix,
- SkScalerContextFlags::kFakeGammaAndBoostContrast,
- &deviceSpecificRec, &effects);
+ auto* glyphCacheState = fStrikeServer->getOrCreateCache(
+ runPaint, &this->surfaceProps(), &runMatrix,
+ SkScalerContextFlags::kFakeGammaAndBoostContrast, &deviceSpecificRec, &effects);
SkASSERT(glyphCacheState);
const bool asPath = false;
@@ -354,53 +383,104 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun(
}
void SkTextBlobCacheDiffCanvas::processGlyphRunForPaths(const SkTextBlobRunIterator& it,
- const SkPaint& runPaint) {
+ const SkPaint& runPaint,
+ const SkMatrix& runMatrix) {
TRACE_EVENT0("skia", "SkTextBlobCacheDiffCanvas::processGlyphRunForPaths");
// The code below borrowed from GrTextContext::DrawBmpPosTextAsPaths.
SkPaint pathPaint(runPaint);
+#if SK_SUPPORT_GPU
+ SkScalar matrixScale = pathPaint.setupForAsPaths();
+ GrTextContext::FallbackTextHelper fallbackTextHelper(runMatrix, runPaint,
+ glyph_size_limit(fSettings), matrixScale);
+ const SkPoint emptyPosition{0, 0};
+#else
pathPaint.setupForAsPaths();
+#endif
+
pathPaint.setStyle(SkPaint::kFill_Style);
pathPaint.setPathEffect(nullptr);
SkScalerContextRec deviceSpecificRec;
SkScalerContextEffects effects;
- auto* glyphCacheState =
- static_cast<SkStrikeServer*>(fStrikeServer)
- ->getOrCreateCache(pathPaint, &this->surfaceProps(), nullptr,
- SkScalerContextFlags::kFakeGammaAndBoostContrast,
- &deviceSpecificRec, &effects);
+ auto* glyphCacheState = fStrikeServer->getOrCreateCache(
+ pathPaint, &this->surfaceProps(), nullptr,
+ SkScalerContextFlags::kFakeGammaAndBoostContrast, &deviceSpecificRec, &effects);
const bool asPath = true;
const SkIPoint subPixelPos{0, 0};
const uint16_t* glyphs = it.glyphs();
for (uint32_t index = 0; index < it.glyphCount(); index++) {
- glyphCacheState->addGlyph(runPaint.getTypeface(),
- effects,
- SkPackedGlyphID(glyphs[index], subPixelPos.x(), subPixelPos.y()),
- asPath);
+ auto glyphID = SkPackedGlyphID(glyphs[index], subPixelPos.x(), subPixelPos.y());
+#if SK_SUPPORT_GPU
+ const auto& glyph = glyphCacheState->findGlyph(runPaint.getTypeface(), effects, glyphID);
+ if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
+ // Note that we send data for the original glyph even in the case of fallback since its
+ // glyph metrics will still be used on the client.
+ fallbackTextHelper.appendText(glyph, sizeof(uint16_t), (const char*)&glyphs[index],
+ emptyPosition);
+ }
+#endif
+ glyphCacheState->addGlyph(runPaint.getTypeface(), effects, glyphID, asPath);
}
+
+#if SK_SUPPORT_GPU
+ add_fallback_text_to_cache(fallbackTextHelper, this->surfaceProps(), runMatrix, runPaint,
+ fStrikeServer);
+#endif
}
-void SkTextBlobCacheDiffCanvas::processGlyphRunForDFT(const SkTextBlobRunIterator& it,
+#if SK_SUPPORT_GPU
+bool SkTextBlobCacheDiffCanvas::processGlyphRunForDFT(const SkTextBlobRunIterator& it,
const SkPaint& runPaint,
- SkScalerContextFlags flags) {
+ const SkMatrix& runMatrix) {
+ GrTextContext::Options options;
+ options.fMinDistanceFieldFontSize = fSettings.fMinDistanceFieldFontSize;
+ options.fMaxDistanceFieldFontSize = fSettings.fMaxDistanceFieldFontSize;
+ GrTextContext::SanitizeOptions(&options);
+ if (!GrTextContext::CanDrawAsDistanceFields(runPaint, runMatrix, this->surfaceProps(),
+ fSettings.fContextSupportsDistanceFieldText,
+ options)) {
+ return false;
+ }
+
+ SkScalar textRatio;
+ SkPaint dfPaint(runPaint);
+ SkScalerContextFlags flags;
+ GrTextContext::InitDistanceFieldPaint(nullptr, &dfPaint, runMatrix, options, &textRatio,
+ &flags);
SkScalerContextRec deviceSpecificRec;
SkScalerContextEffects effects;
- auto* glyphCacheState = static_cast<SkStrikeServer*>(fStrikeServer)
- ->getOrCreateCache(runPaint, &this->surfaceProps(), nullptr,
- flags, &deviceSpecificRec, &effects);
+ auto* glyphCacheState = fStrikeServer->getOrCreateCache(dfPaint, &this->surfaceProps(), nullptr,
+ flags, &deviceSpecificRec, &effects);
+ GrTextContext::FallbackTextHelper fallbackTextHelper(runMatrix, runPaint,
+ glyph_size_limit(fSettings), textRatio);
const bool asPath = false;
const SkIPoint subPixelPos{0, 0};
+ const SkPoint emptyPosition{0, 0};
const uint16_t* glyphs = it.glyphs();
for (uint32_t index = 0; index < it.glyphCount(); index++) {
+ auto glyphID = SkPackedGlyphID(glyphs[index], subPixelPos.x(), subPixelPos.y());
+ const auto& glyph = glyphCacheState->findGlyph(runPaint.getTypeface(), effects, glyphID);
+ if (glyph.fMaskFormat != SkMask::kSDF_Format) {
+ // Note that we send data for the original glyph even in the case of fallback since its
+ // glyph metrics will still be used on the client.
+ fallbackTextHelper.appendText(glyph, sizeof(uint16_t), (const char*)&glyphs[index],
+ emptyPosition);
+ }
+
glyphCacheState->addGlyph(runPaint.getTypeface(),
effects,
SkPackedGlyphID(glyphs[index], subPixelPos.x(), subPixelPos.y()),
asPath);
}
+
+ add_fallback_text_to_cache(fallbackTextHelper, this->surfaceProps(), runMatrix, runPaint,
+ fStrikeServer);
+ return true;
}
+#endif
const SkSurfaceProps& SkTextBlobCacheDiffCanvas::surfaceProps() const {
// SaveLayers can change the SurfaceProps used, and we ensure that the props used by the top
@@ -460,13 +540,6 @@ void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
for (const auto* desc : fLockedDescs) {
auto it = fRemoteGlyphStateMap.find(desc);
SkASSERT(it != fRemoteGlyphStateMap.end());
-
- // TODO: This is unnecessary, write only the descs which has any glyphs
- // to send. It was getting awkward to write the size after writing the
- // descs because the vector reallocs.
- serializer.emplace<bool>(it->second->has_pending_glyphs());
- if (!it->second->has_pending_glyphs()) continue;
-
it->second->writePendingGlyphs(&serializer);
}
fLockedDescs.clear();
@@ -499,7 +572,7 @@ SkStrikeServer::SkGlyphCacheState* SkStrikeServer::getOrCreateCache(
auto it = fRemoteGlyphStateMap.find(keyDesc.get());
if (it != fRemoteGlyphStateMap.end()) {
SkASSERT(it->second->getDeviceDescriptor() == *deviceDesc);
- bool locked = fDiscardableHandleManager->lockHandle(it->second->discardable_handle_id());
+ bool locked = fDiscardableHandleManager->lockHandle(it->second->discardableHandleId());
if (locked) {
fLockedDescs.insert(it->first);
return it->second.get();
@@ -532,10 +605,10 @@ SkStrikeServer::SkGlyphCacheState* SkStrikeServer::getOrCreateCache(
SkStrikeServer::SkGlyphCacheState::SkGlyphCacheState(std::unique_ptr<SkDescriptor> deviceDescriptor,
std::unique_ptr<SkDescriptor>
keyDescriptor,
- uint32_t discardable_handle_id)
+ uint32_t discardableHandleId)
: fDeviceDescriptor(std::move(deviceDescriptor))
, fKeyDescriptor(std::move(keyDescriptor))
- , fDiscardableHandleId(discardable_handle_id) {
+ , fDiscardableHandleId(discardableHandleId) {
SkASSERT(fDeviceDescriptor);
SkASSERT(fKeyDescriptor);
}
@@ -562,6 +635,13 @@ void SkStrikeServer::SkGlyphCacheState::addGlyph(SkTypeface* typeface,
}
void SkStrikeServer::SkGlyphCacheState::writePendingGlyphs(Serializer* serializer) {
+ // TODO(khushalsagar): Write a strike only if it has any pending glyphs.
+ serializer->emplace<bool>(this->hasPendingGlyphs());
+ if (!this->hasPendingGlyphs()) {
+ fContext.reset();
+ return;
+ }
+
// Write the desc.
serializer->emplace<StrikeSpec>(fContext->getTypeface()->uniqueID(), fDiscardableHandleId);
serializer->writeDescriptor(*fKeyDescriptor.get());
@@ -622,6 +702,21 @@ void SkStrikeServer::SkGlyphCacheState::writePendingGlyphs(Serializer* serialize
fContext.reset();
}
+const SkGlyph& SkStrikeServer::SkGlyphCacheState::findGlyph(SkTypeface* tf,
+ const SkScalerContextEffects& effects,
+ SkPackedGlyphID glyphID) {
+ auto* glyph = fGlyphMap.find(glyphID);
+ if (glyph) return *glyph;
+
+ glyph = fGlyphMap.set(glyphID, SkGlyph());
+ glyph->initWithGlyphID(glyphID);
+ if (!fContext) {
+ fContext = tf->createScalerContext(effects, fDeviceDescriptor.get(), false);
+ }
+ fContext->getMetrics(glyph);
+ return *glyph;
+}
+
void SkStrikeServer::SkGlyphCacheState::writeGlyphPath(const SkPackedGlyphID& glyphID,
Serializer* serializer) const {
SkPath path;
diff --git a/src/core/SkRemoteGlyphCache.h b/src/core/SkRemoteGlyphCache.h
index 4fa4e0afc1..2772de67cb 100644
--- a/src/core/SkRemoteGlyphCache.h
+++ b/src/core/SkRemoteGlyphCache.h
@@ -59,6 +59,8 @@ public:
bool fContextSupportsDistanceFieldText = true;
SkScalar fMinDistanceFieldFontSize = -1.f;
SkScalar fMaxDistanceFieldFontSize = -1.f;
+ int fMaxTextureSize = 0;
+ size_t fMaxTextureBytes = 0u;
};
SkTextBlobCacheDiffCanvas(int width, int height, const SkMatrix& deviceMatrix,
const SkSurfaceProps& props, SkStrikeServer* strikeserver,
@@ -79,9 +81,12 @@ private:
void processGlyphRun(const SkPoint& position,
const SkTextBlobRunIterator& it,
const SkPaint& runPaint);
- void processGlyphRunForPaths(const SkTextBlobRunIterator& it, const SkPaint& runPaint);
- void processGlyphRunForDFT(const SkTextBlobRunIterator& it, const SkPaint& runPaint,
- SkScalerContextFlags flags);
+ void processGlyphRunForPaths(const SkTextBlobRunIterator& it, const SkPaint& runPaint,
+ const SkMatrix& runMatrix);
+#if SK_SUPPORT_GPU
+ bool processGlyphRunForDFT(const SkTextBlobRunIterator& it, const SkPaint& runPaint,
+ const SkMatrix& runMatrix);
+#endif
const SkSurfaceProps& surfaceProps() const;
const SkMatrix fDeviceMatrix;
@@ -138,10 +143,7 @@ public:
void addGlyph(SkTypeface*, const SkScalerContextEffects&, SkPackedGlyphID, bool pathOnly);
void writePendingGlyphs(Serializer* serializer);
- bool has_pending_glyphs() const {
- return !fPendingGlyphImages.empty() || !fPendingGlyphPaths.empty();
- }
- SkDiscardableHandleId discardable_handle_id() const { return fDiscardableHandleId; }
+ SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; }
const SkDescriptor& getDeviceDescriptor() {
return *fDeviceDescriptor;
}
@@ -149,8 +151,12 @@ public:
const SkDescriptor& getKeyDescriptor() {
return *fKeyDescriptor;
}
+ const SkGlyph& findGlyph(SkTypeface*, const SkScalerContextEffects&, SkPackedGlyphID);
private:
+ bool hasPendingGlyphs() const {
+ return !fPendingGlyphImages.empty() || !fPendingGlyphPaths.empty();
+ }
void writeGlyphPath(const SkPackedGlyphID& glyphID, Serializer* serializer) const;
// The set of glyphs cached on the remote client.
@@ -171,6 +177,9 @@ public:
// The context built using fDeviceDescriptor
std::unique_ptr<SkScalerContext> fContext;
+ // FallbackTextHelper cases require glyph metrics when analyzing a glyph run, in which case
+ // we cache them here.
+ SkTHashMap<SkPackedGlyphID, SkGlyph> fGlyphMap;
};
SkGlyphCacheState* getOrCreateCache(const SkPaint&, const SkSurfaceProps*, const SkMatrix*,
@@ -206,7 +215,7 @@ public:
// successful, subsequent attempts to delete the same handle are invalid.
virtual bool deleteHandle(SkDiscardableHandleId) = 0;
- virtual void NotifyCacheMiss(CacheMissType) {}
+ virtual void notifyCacheMiss(CacheMissType) {}
};
SkStrikeClient(sk_sp<DiscardableHandleManager>, bool isLogging = true);
diff --git a/src/core/SkTypeface_remote.cpp b/src/core/SkTypeface_remote.cpp
index b5871ded25..472c009dcc 100644
--- a/src/core/SkTypeface_remote.cpp
+++ b/src/core/SkTypeface_remote.cpp
@@ -38,7 +38,7 @@ void SkScalerContextProxy::generateMetrics(SkGlyph* glyph) {
SkDebugf("GlyphCacheMiss generateMetrics: %s\n", this->getRec().dump().c_str());
}
- fDiscardableManager->NotifyCacheMiss(SkStrikeClient::CacheMissType::kGlyphMetrics);
+ fDiscardableManager->notifyCacheMiss(SkStrikeClient::CacheMissType::kGlyphMetrics);
glyph->zeroMetrics();
}
@@ -48,7 +48,7 @@ void SkScalerContextProxy::generateImage(const SkGlyph& glyph) {
SkDebugf("GlyphCacheMiss generateImage: %s\n", this->getRec().dump().c_str());
}
- fDiscardableManager->NotifyCacheMiss(SkStrikeClient::CacheMissType::kGlyphImage);
+ fDiscardableManager->notifyCacheMiss(SkStrikeClient::CacheMissType::kGlyphImage);
}
bool SkScalerContextProxy::generatePath(SkGlyphID glyphID, SkPath* path) {
@@ -57,7 +57,7 @@ bool SkScalerContextProxy::generatePath(SkGlyphID glyphID, SkPath* path) {
SkDebugf("GlyphCacheMiss generatePath: %s\n", this->getRec().dump().c_str());
}
- fDiscardableManager->NotifyCacheMiss(SkStrikeClient::CacheMissType::kGlyphPath);
+ fDiscardableManager->notifyCacheMiss(SkStrikeClient::CacheMissType::kGlyphPath);
return false;
}
@@ -69,10 +69,10 @@ void SkScalerContextProxy::generateFontMetrics(SkPaint::FontMetrics* metrics) {
SkDEBUGCODE(SkStrikeCache::Dump());
}
- fDiscardableManager->NotifyCacheMiss(SkStrikeClient::CacheMissType::kFontMetrics);
+ fDiscardableManager->notifyCacheMiss(SkStrikeClient::CacheMissType::kFontMetrics);
sk_bzero(metrics, sizeof(*metrics));
}
SkTypefaceProxy* SkScalerContextProxy::getProxyTypeface() const {
return (SkTypefaceProxy*)this->getTypeface();
-} \ No newline at end of file
+}
diff --git a/src/gpu/text/GrAtlasManager.cpp b/src/gpu/text/GrAtlasManager.cpp
index f75224d0bc..ec07429180 100644
--- a/src/gpu/text/GrAtlasManager.cpp
+++ b/src/gpu/text/GrAtlasManager.cpp
@@ -12,15 +12,16 @@
#include "GrGlyphCache.h"
#include "GrProxyProvider.h"
-void GrAtlasManager::ComputeAtlasLimits(const GrCaps* caps, float maxTextureBytes,
- int* maxDim, int* minDim, int* maxPlot, int* minPlot) {
+void GrAtlasManager::ComputeAtlasLimits(int maxTextureSize, size_t maxTextureBytes, int* maxDim,
+ int* minDim, int* maxPlot, int* minPlot) {
SkASSERT(maxDim && minDim && maxPlot && minPlot);
// Calculate RGBA size. Must be between 512 x 256 and MaxTextureSize x MaxTextureSize / 2
- int log2MaxTextureSize = SkPrevLog2(caps->maxTextureSize());
+ int log2MaxTextureSize = SkPrevLog2(maxTextureSize);
int log2MaxDim = 9;
+ static const size_t kOne = 1u;
for (; log2MaxDim <= log2MaxTextureSize; ++log2MaxDim) {
- int maxDimTmp = 1 << log2MaxDim;
- int minDimTmp = 1 << (log2MaxDim - 1);
+ size_t maxDimTmp = kOne << log2MaxDim;
+ size_t minDimTmp = kOne << (log2MaxDim - 1);
if (maxDimTmp * minDimTmp * 4 >= maxTextureBytes) {
break;
@@ -45,7 +46,8 @@ GrAtlasManager::GrAtlasManager(GrProxyProvider* proxyProvider, GrGlyphCache* gly
fCaps = fProxyProvider->refCaps();
int maxDim, minDim, maxPlot, minPlot;
- ComputeAtlasLimits(fCaps.get(), maxTextureBytes, &maxDim, &minDim, &maxPlot, &minPlot);
+ ComputeAtlasLimits(fCaps->maxTextureSize(), maxTextureBytes, &maxDim, &minDim, &maxPlot,
+ &minPlot);
// Setup default atlas configs. The A8 atlas uses maxDim for both width and height, as the A8
// format is already very compact.
diff --git a/src/gpu/text/GrAtlasManager.h b/src/gpu/text/GrAtlasManager.h
index 18ccfd096f..38e2781d4d 100644
--- a/src/gpu/text/GrAtlasManager.h
+++ b/src/gpu/text/GrAtlasManager.h
@@ -43,8 +43,8 @@ public:
SkScalar getGlyphSizeLimit() const { return fGlyphSizeLimit; }
- static void ComputeAtlasLimits(const GrCaps* caps, float maxTextureBytes,
- int* maxDim, int* minDim, int* maxPlot, int* minPlot);
+ static void ComputeAtlasLimits(int maxTextureSize, size_t maxTextureBytes, int* maxDim,
+ int* minDim, int* maxPlot, int* minPlot);
void freeAll();
diff --git a/src/gpu/text/GrGlyphCache.cpp b/src/gpu/text/GrGlyphCache.cpp
index b564c93c02..f6a18c3271 100644
--- a/src/gpu/text/GrGlyphCache.cpp
+++ b/src/gpu/text/GrGlyphCache.cpp
@@ -5,20 +5,17 @@
* found in the LICENSE file.
*/
+#include "GrGlyphCache.h"
#include "GrAtlasManager.h"
+#include "GrCaps.h"
#include "GrDistanceFieldGenFromVector.h"
-#include "GrGlyphCache.h"
#include "SkAutoMalloc.h"
#include "SkDistanceFieldGen.h"
-GrGlyphCache::GrGlyphCache(const GrCaps* caps, float maxTextureBytes)
- : fPreserveStrike(nullptr)
- , fGlyphSizeLimit(0) {
-
- int maxDim, minDim, maxPlot, minPlot;
- GrAtlasManager::ComputeAtlasLimits(caps, maxTextureBytes, &maxDim, &minDim, &maxPlot, &minPlot);
- fGlyphSizeLimit = minPlot;
+GrGlyphCache::GrGlyphCache(const GrCaps* caps, size_t maxTextureBytes)
+ : fPreserveStrike(nullptr), fGlyphSizeLimit(0) {
+ fGlyphSizeLimit = ComputeGlyphSizeLimit(caps->maxTextureSize(), maxTextureBytes);
}
GrGlyphCache::~GrGlyphCache() {
@@ -40,6 +37,13 @@ void GrGlyphCache::freeAll() {
fCache.rewind();
}
+SkScalar GrGlyphCache::ComputeGlyphSizeLimit(int maxTextureSize, size_t maxTextureBytes) {
+ int maxDim, minDim, maxPlot, minPlot;
+ GrAtlasManager::ComputeAtlasLimits(maxTextureSize, maxTextureBytes, &maxDim, &minDim, &maxPlot,
+ &minPlot);
+ return minPlot;
+}
+
void GrGlyphCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) {
GrGlyphCache* glyphCache = reinterpret_cast<GrGlyphCache*>(ptr);
diff --git a/src/gpu/text/GrGlyphCache.h b/src/gpu/text/GrGlyphCache.h
index cff309501d..7e707ec64c 100644
--- a/src/gpu/text/GrGlyphCache.h
+++ b/src/gpu/text/GrGlyphCache.h
@@ -108,7 +108,7 @@ private:
*/
class GrGlyphCache {
public:
- GrGlyphCache(const GrCaps* caps, float maxTextureBytes);
+ GrGlyphCache(const GrCaps* caps, size_t maxTextureBytes);
~GrGlyphCache();
SkScalar getGlyphSizeLimit() const { return fGlyphSizeLimit; }
@@ -130,6 +130,7 @@ public:
void freeAll();
static void HandleEviction(GrDrawOpAtlas::AtlasID, void*);
+ static SkScalar ComputeGlyphSizeLimit(int maxTextureSize, size_t maxTextureBytes);
private:
sk_sp<GrTextStrike> generateStrike(const SkGlyphCache* cache) {
diff --git a/src/gpu/text/GrTextContext.cpp b/src/gpu/text/GrTextContext.cpp
index 033506f220..9864d027de 100644
--- a/src/gpu/text/GrTextContext.cpp
+++ b/src/gpu/text/GrTextContext.cpp
@@ -380,7 +380,8 @@ void GrTextContext::DrawBmpPosTextAsPaths(GrTextBlob* blob, int runIndex,
// setup our std paint, in hopes of getting hits in the cache
SkPaint pathPaint(origPaint);
SkScalar matrixScale = pathPaint.setupForAsPaths();
- FallbackTextHelper fallbackTextHelper(viewMatrix, origPaint, glyphCache, matrixScale);
+ FallbackTextHelper fallbackTextHelper(viewMatrix, origPaint, glyphCache->getGlyphSizeLimit(),
+ matrixScale);
// Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
pathPaint.setStyle(SkPaint::kFill_Style);
@@ -596,7 +597,8 @@ void GrTextContext::drawDFPosText(GrTextBlob* blob, int runIndex,
blob->setSubRunHasDistanceFields(runIndex, paint.skPaint().isLCDRenderText(),
paint.skPaint().isAntiAlias(), hasWCoord);
- FallbackTextHelper fallbackTextHelper(viewMatrix, paint, glyphCache, textRatio);
+ FallbackTextHelper fallbackTextHelper(viewMatrix, paint, glyphCache->getGlyphSizeLimit(),
+ textRatio);
sk_sp<GrTextStrike> currStrike;
@@ -672,6 +674,8 @@ void GrTextContext::DfAppendGlyph(GrTextBlob* blob, int runIndex,
void GrTextContext::FallbackTextHelper::appendText(const SkGlyph& glyph, int count,
const char* text, SkPoint glyphPos) {
SkScalar maxDim = SkTMax(glyph.fWidth, glyph.fHeight)*fTextRatio;
+ if (SkScalarNearlyZero(maxDim)) return;
+
if (!fUseTransformedFallback) {
if (!fViewMatrix.isScaleTranslate() || maxDim*fMaxScale > fMaxTextSize) {
fUseTransformedFallback = true;
@@ -706,18 +710,12 @@ void GrTextContext::FallbackTextHelper::drawText(GrTextBlob* blob, int runIndex,
SkPaint::GlyphCacheProc glyphCacheProc =
SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(), true);
SkColor textColor = paint.filteredPremulColor();
+
SkScalar textRatio = SK_Scalar1;
- if (fUseTransformedFallback) {
- // Set up paint and matrix to scale glyphs
- SkPaint scaledPaint(skPaint);
- scaledPaint.setTextSize(fTransformedFallbackTextSize);
- textRatio = fTextSize / fTransformedFallbackTextSize;
- cache = blob->setupCache(runIndex, props, scalerContextFlags, scaledPaint,
- &SkMatrix::I());
- } else {
- cache = blob->setupCache(runIndex, props, scalerContextFlags, paint,
- &fViewMatrix);
- }
+ SkPaint fallbackPaint(skPaint);
+ SkMatrix matrix = fViewMatrix;
+ this->initializeForDraw(&fallbackPaint, &textRatio, &matrix);
+ cache = blob->setupCache(runIndex, props, scalerContextFlags, fallbackPaint, &matrix);
sk_sp<GrTextStrike> currStrike;
const char* text = fFallbackTxt.begin();
@@ -738,6 +736,15 @@ void GrTextContext::FallbackTextHelper::drawText(GrTextBlob* blob, int runIndex,
}
}
+void GrTextContext::FallbackTextHelper::initializeForDraw(SkPaint* paint, SkScalar* textRatio,
+ SkMatrix* matrix) const {
+ if (!fUseTransformedFallback) return;
+
+ paint->setTextSize(fTransformedFallbackTextSize);
+ *textRatio = fTextSize / fTransformedFallbackTextSize;
+ *matrix = SkMatrix::I();
+}
+
///////////////////////////////////////////////////////////////////////////////////////////////////
#if GR_TEST_UTILS
diff --git a/src/gpu/text/GrTextContext.h b/src/gpu/text/GrTextContext.h
index 7d31d84a05..478d4c42b6 100644
--- a/src/gpu/text/GrTextContext.h
+++ b/src/gpu/text/GrTextContext.h
@@ -69,21 +69,18 @@ public:
SkScalar* textRatio,
SkScalerContextFlags* flags);
-private:
- GrTextContext(const Options& options);
-
class FallbackTextHelper {
public:
FallbackTextHelper(const SkMatrix& viewMatrix,
const SkPaint& pathPaint,
- const GrGlyphCache* glyphCache,
+ SkScalar maxTextSize,
SkScalar textRatio)
- : fViewMatrix(viewMatrix)
- , fTextSize(pathPaint.getTextSize())
- , fMaxTextSize(glyphCache->getGlyphSizeLimit())
- , fTextRatio(textRatio)
- , fTransformedFallbackTextSize(fMaxTextSize)
- , fUseTransformedFallback(false) {
+ : fViewMatrix(viewMatrix)
+ , fTextSize(pathPaint.getTextSize())
+ , fMaxTextSize(maxTextSize)
+ , fTextRatio(textRatio)
+ , fTransformedFallbackTextSize(fMaxTextSize)
+ , fUseTransformedFallback(false) {
fMaxScale = viewMatrix.getMaxScale();
}
@@ -91,6 +88,9 @@ private:
void drawText(GrTextBlob* blob, int runIndex, GrGlyphCache*, const SkSurfaceProps&,
const GrTextUtils::Paint&, SkScalerContextFlags);
+ void initializeForDraw(SkPaint* paint, SkScalar* textRatio, SkMatrix* matrix) const;
+ const SkTDArray<char>& fallbackText() const { return fFallbackTxt; }
+
private:
SkTDArray<char> fFallbackTxt;
SkTDArray<SkPoint> fFallbackPos;
@@ -104,6 +104,9 @@ private:
bool fUseTransformedFallback;
};
+private:
+ GrTextContext(const Options& options);
+
// sets up the descriptor on the blob and returns a detached cache. Client must attach
static SkColor ComputeCanonicalColor(const SkPaint&, bool lcd);
// Determines if we need to use fake gamma (and contrast boost):
diff --git a/tests/SkRemoteGlyphCacheTest.cpp b/tests/SkRemoteGlyphCacheTest.cpp
index 013eead9db..af73158eb9 100644
--- a/tests/SkRemoteGlyphCacheTest.cpp
+++ b/tests/SkRemoteGlyphCacheTest.cpp
@@ -37,7 +37,7 @@ public:
// Client implementation.
bool deleteHandle(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; }
- void NotifyCacheMiss(SkStrikeClient::CacheMissType type) override { fCacheMissCount[type]++; }
+ void notifyCacheMiss(SkStrikeClient::CacheMissType type) override { fCacheMissCount[type]++; }
void unlockAll() { fLockedHandles.reset(); }
void unlockAndDeleteAll() {
@@ -47,6 +47,12 @@ public:
const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const { return fLockedHandles; }
SkDiscardableHandleId handleCount() { return fNextHandleId; }
int cacheMissCount(SkStrikeClient::CacheMissType type) { return fCacheMissCount[type]; }
+ bool hasCacheMiss() const {
+ for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
+ if (fCacheMissCount[i] > 0) return true;
+ }
+ return false;
+ }
private:
SkDiscardableHandleId fNextHandleId = 0u;
@@ -87,6 +93,8 @@ sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
SkTextBlobCacheDiffCanvas::Settings MakeSettings(GrContext* context) {
SkTextBlobCacheDiffCanvas::Settings settings;
settings.fContextSupportsDistanceFieldText = context->supportsDistanceFieldText();
+ settings.fMaxTextureSize = context->maxTextureSize();
+ settings.fMaxTextureBytes = GrContextOptions().fGlyphCacheTextureMaximumBytes;
return settings;
}
@@ -149,6 +157,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, repor
SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
COMPARE_BLOBS(expected, actual, reporter);
+ REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
// Must unlock everything on termination, otherwise valgrind complains about memory leaks.
discardableManager->unlockAndDeleteAll();
@@ -316,6 +325,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter,
SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
COMPARE_BLOBS(expected, actual, reporter);
+ REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
SkStrikeCache::Validate();
// Must unlock everything on termination, otherwise valgrind complains about memory leaks.
@@ -362,6 +372,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, c
SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
COMPARE_BLOBS(expected, actual, reporter);
+ REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
SkStrikeCache::Validate();
// Must unlock everything on termination, otherwise valgrind complains about memory leaks.