diff options
author | Khushal <khushalsagar@chromium.org> | 2018-06-06 17:46:38 -0700 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-06-07 18:03:11 +0000 |
commit | fa8ff09457f82119be0d00b7f37afb790487819e (patch) | |
tree | 65ee0f8eff9997add651bf8f3b48ac74b4413cdf | |
parent | d5b4593024544c3405615066aa5b4f94352eb3cb (diff) |
fonts: Hook up FallbackTextHelper to font remoting.
Use GrContext::FallbackTextHelper in SkTextBlobCacheDiffCanvas to
replicate glyph generation logic for fallback text during analysis. This
ensures that we correctly handle these fallback cases when using
distance field or paths for text rendering.
R=herb@google.com, jvanverth@google.com
Bug: skia:7913
Change-Id: I3067c4f1bd09231a564ac7c4cd89efcb876d2abd
Reviewed-on: https://skia-review.googlesource.com/132285
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Khusal Sagar <khushalsagar@chromium.org>
-rw-r--r-- | include/gpu/GrContextOptions.h | 2 | ||||
-rw-r--r-- | src/core/SkRemoteGlyphCache.cpp | 185 | ||||
-rw-r--r-- | src/core/SkRemoteGlyphCache.h | 25 | ||||
-rw-r--r-- | src/core/SkTypeface_remote.cpp | 10 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasManager.cpp | 14 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasManager.h | 4 | ||||
-rw-r--r-- | src/gpu/text/GrGlyphCache.cpp | 20 | ||||
-rw-r--r-- | src/gpu/text/GrGlyphCache.h | 3 | ||||
-rw-r--r-- | src/gpu/text/GrTextContext.cpp | 33 | ||||
-rw-r--r-- | src/gpu/text/GrTextContext.h | 23 | ||||
-rw-r--r-- | tests/SkRemoteGlyphCacheTest.cpp | 13 |
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. |