xref: /aosp_15_r20/external/skia/src/text/gpu/TextBlobRedrawCoordinator.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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