diff options
-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. |