1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef sktext_gpu_TextBlobRedrawCoordinator_DEFINED 9 #define sktext_gpu_TextBlobRedrawCoordinator_DEFINED 10 11 #include "include/core/SkRefCnt.h" 12 #include "include/private/base/SkTArray.h" 13 #include "include/private/base/SkThreadAnnotations.h" 14 #include "src/base/SkSpinlock.h" 15 #include "src/base/SkTInternalLList.h" 16 #include "src/core/SkMessageBus.h" 17 #include "src/core/SkTHash.h" 18 #include "src/text/gpu/SubRunContainer.h" 19 #include "src/text/gpu/TextBlob.h" 20 21 #include <cstddef> 22 #include <cstdint> 23 24 class GrTextBlobTestingPeer; 25 class SkCanvas; 26 class SkMatrix; 27 class SkPaint; 28 struct SkStrikeDeviceInfo; 29 30 namespace sktext { class GlyphRunList; } 31 32 namespace sktext::gpu { 33 34 // TextBlobRedrawCoordinator reuses data from previous drawing operations using multiple criteria 35 // to pick the best data for the draw. In addition, it provides a central service for managing 36 // resource usage through a messageBus. 37 // The draw data is stored in a three-tiered system. The first tier is keyed by the SkTextBlob's 38 // uniqueID. The second tier uses the sktext::gpu::TextBlob's key to get a general match for the 39 // draw. The last tier queries each sub run using canReuse to determine if each sub run can handle 40 // the drawing parameters. 41 class TextBlobRedrawCoordinator { 42 public: 43 TextBlobRedrawCoordinator(uint32_t messageBusID); 44 45 void drawGlyphRunList(SkCanvas* canvas, 46 const SkMatrix& viewMatrix, 47 const GlyphRunList& glyphRunList, 48 const SkPaint& paint, 49 SkStrikeDeviceInfo strikeDeviceInfo, 50 const AtlasDrawDelegate&); 51 52 void freeAll() SK_EXCLUDES(fSpinLock); 53 54 struct PurgeBlobMessage { PurgeBlobMessagePurgeBlobMessage55 PurgeBlobMessage(uint32_t blobID, uint32_t contextUniqueID) 56 : fBlobID(blobID), fContextID(contextUniqueID) {} 57 58 uint32_t fBlobID; 59 uint32_t fContextID; 60 }; 61 62 void purgeStaleBlobs() SK_EXCLUDES(fSpinLock); 63 64 size_t usedBytes() const SK_EXCLUDES(fSpinLock); 65 66 bool isOverBudget() const SK_EXCLUDES(fSpinLock); 67 68 private: 69 friend class ::GrTextBlobTestingPeer; 70 using TextBlobList = SkTInternalLList<TextBlob>; 71 72 struct BlobIDCacheEntry { 73 BlobIDCacheEntry(); 74 explicit BlobIDCacheEntry(uint32_t id); 75 76 static uint32_t GetKey(const BlobIDCacheEntry& entry); 77 78 void addBlob(sk_sp<TextBlob> blob); 79 80 void removeBlob(TextBlob* blob); 81 82 sk_sp<TextBlob> find(const TextBlob::Key& key) const; 83 84 int findBlobIndex(const TextBlob::Key& key) const; 85 86 uint32_t fID; 87 // Current clients don't generate multiple GrAtlasTextBlobs per SkTextBlob, so an array w/ 88 // linear search is acceptable. If usage changes, we should re-evaluate this structure. 89 skia_private::STArray<1, sk_sp<TextBlob>> fBlobs; 90 }; 91 92 sk_sp<TextBlob> findOrCreateBlob(const SkMatrix& positionMatrix, 93 const GlyphRunList& glyphRunList, 94 const SkPaint& paint, 95 SkStrikeDeviceInfo strikeDeviceInfo); 96 97 // If not already in the cache, then add it else, return the text blob from the cache. 98 sk_sp<TextBlob> addOrReturnExisting( 99 const GlyphRunList& glyphRunList, 100 sk_sp<TextBlob> blob) SK_EXCLUDES(fSpinLock); 101 102 sk_sp<TextBlob> find(const TextBlob::Key& key) SK_EXCLUDES(fSpinLock); 103 104 void remove(TextBlob* blob) SK_EXCLUDES(fSpinLock); 105 106 void internalPurgeStaleBlobs() SK_REQUIRES(fSpinLock); 107 108 sk_sp<TextBlob> 109 internalAdd(sk_sp<TextBlob> blob) SK_REQUIRES(fSpinLock); 110 void internalRemove(TextBlob* blob) SK_REQUIRES(fSpinLock); 111 112 void internalCheckPurge(TextBlob* blob = nullptr) SK_REQUIRES(fSpinLock); 113 114 static const int kDefaultBudget = 1 << 22; 115 116 mutable SkSpinlock fSpinLock; 117 TextBlobList fBlobList SK_GUARDED_BY(fSpinLock); 118 skia_private::THashMap<uint32_t, BlobIDCacheEntry> fBlobIDCache SK_GUARDED_BY(fSpinLock); 119 size_t fSizeBudget SK_GUARDED_BY(fSpinLock); SK_GUARDED_BY(fSpinLock)120 size_t fCurrentSize SK_GUARDED_BY(fSpinLock) {0}; 121 122 // In practice 'messageBusID' is always the unique ID of the owning GrContext 123 const uint32_t fMessageBusID; 124 SkMessageBus<PurgeBlobMessage, uint32_t>::Inbox fPurgeBlobInbox SK_GUARDED_BY(fSpinLock); 125 }; 126 127 } // namespace sktext::gpu 128 129 #endif // sktext_gpu_TextBlobRedrawCoordinator_DEFINED 130