• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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 GrLayerCache_DEFINED
9 #define GrLayerCache_DEFINED
10 
11 #include "GrAtlas.h"
12 #include "GrPictureUtils.h"
13 #include "GrRect.h"
14 #include "SkChecksum.h"
15 #include "SkTDynamicHash.h"
16 #include "SkMessageBus.h"
17 
18 class SkPicture;
19 
20 // The layer cache listens for these messages to purge picture-related resources.
21 struct GrPictureDeletedMessage {
22     uint32_t pictureID;
23 };
24 
25 // GrPictureInfo stores the atlas plots used by a single picture. A single
26 // plot may be used to store layers from multiple pictures.
27 struct GrPictureInfo {
28 public:
29     // for SkTDynamicHash - just use the pictureID as the hash key
GetKeyGrPictureInfo30     static const uint32_t& GetKey(const GrPictureInfo& pictInfo) { return pictInfo.fPictureID; }
HashGrPictureInfo31     static uint32_t Hash(const uint32_t& key) { return SkChecksum::Mix(key); }
32 
33     // GrPictureInfo proper
GrPictureInfoGrPictureInfo34     GrPictureInfo(uint32_t pictureID) : fPictureID(pictureID) { }
35 
36     const uint32_t fPictureID;
37 
38     GrAtlas::ClientPlotUsage  fPlotUsage;
39 };
40 
41 // GrCachedLayer encapsulates the caching information for a single saveLayer.
42 //
43 // Atlased layers get a ref to the backing GrTexture while non-atlased layers
44 // get a ref to the GrTexture in which they reside. In both cases 'fRect'
45 // contains the layer's extent in its texture.
46 // Atlased layers also get a pointer to the plot in which they reside.
47 // For non-atlased layers, the lock field just corresponds to locking in
48 // the resource cache. For atlased layers, it implements an additional level
49 // of locking to allow atlased layers to be reused multiple times.
50 struct GrCachedLayer {
51 public:
52     // For SkTDynamicHash
53     struct Key {
KeyGrCachedLayer::Key54         Key(uint32_t pictureID, int start, int stop, const SkIPoint& offset, const SkMatrix& ctm)
55         : fPictureID(pictureID)
56         , fStart(start)
57         , fStop(stop)
58         , fOffset(offset)
59         , fCTM(ctm) {
60             fCTM.getType(); // force initialization of type so hashes match
61 
62             // Key needs to be tightly packed.
63             GR_STATIC_ASSERT(sizeof(Key) == sizeof(uint32_t) + 2 * sizeof(int) +
64                                             2 * sizeof(int32_t) +
65                                             9 * sizeof(SkScalar) + sizeof(uint32_t));
66         }
67 
68         bool operator==(const Key& other) const {
69             return fPictureID == other.fPictureID &&
70                    fStart == other.fStart &&
71                    fStop == other.fStop &&
72                    fOffset == other.fOffset &&
73                    fCTM.cheapEqualTo(other.fCTM);
74         }
75 
pictureIDGrCachedLayer::Key76         uint32_t pictureID() const { return fPictureID; }
startGrCachedLayer::Key77         int start() const { return fStart; }
stopGrCachedLayer::Key78         int stop() const { return fStop; }
offsetGrCachedLayer::Key79         const SkIPoint& offset() const { return fOffset; }
ctmGrCachedLayer::Key80         const SkMatrix& ctm() const { return fCTM; }
81 
82     private:
83         // ID of the picture of which this layer is a part
84         const uint32_t fPictureID;
85         // The range of commands in the picture this layer represents
86         const int      fStart;
87         const int      fStop;
88         // The offset of the layer in device space
89         const SkIPoint fOffset;
90         // The CTM applied to this layer in the picture
91         SkMatrix       fCTM;
92     };
93 
GetKeyGrCachedLayer94     static const Key& GetKey(const GrCachedLayer& layer) { return layer.fKey; }
HashGrCachedLayer95     static uint32_t Hash(const Key& key) {
96         return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
97     }
98 
99     // GrCachedLayer proper
GrCachedLayerGrCachedLayer100     GrCachedLayer(uint32_t pictureID, int start, int stop,
101                   const SkIPoint& offset, const SkMatrix& ctm,
102                   const SkPaint* paint)
103         : fKey(pictureID, start, stop, offset, ctm)
104         , fPaint(paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL)
105         , fTexture(NULL)
106         , fRect(GrIRect16::MakeEmpty())
107         , fPlot(NULL)
108         , fLocked(false) {
109         SkASSERT(SK_InvalidGenID != pictureID && start >= 0 && stop >= 0);
110     }
111 
~GrCachedLayerGrCachedLayer112     ~GrCachedLayer() {
113         SkSafeUnref(fTexture);
114         SkDELETE(fPaint);
115     }
116 
pictureIDGrCachedLayer117     uint32_t pictureID() const { return fKey.pictureID(); }
startGrCachedLayer118     int start() const { return fKey.start(); }
stopGrCachedLayer119     int stop() const { return fKey.stop(); }
offsetGrCachedLayer120     const SkIPoint& offset() const { return fKey.offset(); }
ctmGrCachedLayer121     const SkMatrix& ctm() const { return fKey.ctm(); }
122 
setTextureGrCachedLayer123     void setTexture(GrTexture* texture, const GrIRect16& rect) {
124         SkRefCnt_SafeAssign(fTexture, texture);
125         fRect = rect;
126     }
textureGrCachedLayer127     GrTexture* texture() { return fTexture; }
paintGrCachedLayer128     const SkPaint* paint() const { return fPaint; }
rectGrCachedLayer129     const GrIRect16& rect() const { return fRect; }
130 
setPlotGrCachedLayer131     void setPlot(GrPlot* plot) {
132         SkASSERT(NULL == plot || NULL == fPlot);
133         fPlot = plot;
134     }
plotGrCachedLayer135     GrPlot* plot() { return fPlot; }
136 
isAtlasedGrCachedLayer137     bool isAtlased() const { return SkToBool(fPlot); }
138 
setLockedGrCachedLayer139     void setLocked(bool locked) { fLocked = locked; }
lockedGrCachedLayer140     bool locked() const { return fLocked; }
141 
142     SkDEBUGCODE(const GrPlot* plot() const { return fPlot; })
143     SkDEBUGCODE(void validate(const GrTexture* backingTexture) const;)
144 
145 private:
146     const Key       fKey;
147 
148     // The paint used when dropping the layer down into the owning canvas.
149     // Can be NULL. This class makes a copy for itself.
150     const SkPaint*  fPaint;
151 
152     // fTexture is a ref on the atlasing texture for atlased layers and a
153     // ref on a GrTexture for non-atlased textures.
154     GrTexture*      fTexture;
155 
156     // For both atlased and non-atlased layers 'fRect' contains the  bound of
157     // the layer in whichever texture it resides. It is empty when 'fTexture'
158     // is NULL.
159     GrIRect16       fRect;
160 
161     // For atlased layers, fPlot stores the atlas plot in which the layer rests.
162     // It is always NULL for non-atlased layers.
163     GrPlot*         fPlot;
164 
165     // For non-atlased layers 'fLocked' should always match "fTexture".
166     // (i.e., if there is a texture it is locked).
167     // For atlased layers, 'fLocked' is true if the layer is in a plot and
168     // actively required for rendering. If the layer is in a plot but not
169     // actively required for rendering, then 'fLocked' is false. If the
170     // layer isn't in a plot then is can never be locked.
171     bool            fLocked;
172 };
173 
174 // The GrLayerCache caches pre-computed saveLayers for later rendering.
175 // Non-atlased layers are stored in their own GrTexture while the atlased
176 // layers share a single GrTexture.
177 // Unlike the GrFontCache, the GrTexture atlas only has one GrAtlas (for 8888)
178 // and one GrPlot (for the entire atlas). As such, the GrLayerCache
179 // roughly combines the functionality of the GrFontCache and GrTextStrike
180 // classes.
181 class GrLayerCache {
182 public:
183     GrLayerCache(GrContext*);
184     ~GrLayerCache();
185 
186     // As a cache, the GrLayerCache can be ordered to free up all its cached
187     // elements by the GrContext
188     void freeAll();
189 
190     GrCachedLayer* findLayer(uint32_t pictureID, int start, int stop,
191                              const SkIPoint& offset, const SkMatrix& ctm);
192     GrCachedLayer* findLayerOrCreate(uint32_t pictureID,
193                                      int start, int stop,
194                                      const SkIPoint& offset,
195                                      const SkMatrix& ctm,
196                                      const SkPaint* paint);
197 
198     // Inform the cache that layer's cached image is now required.
199     // Return true if the layer must be re-rendered. Return false if the
200     // layer was found in the cache and can be reused.
201     bool lock(GrCachedLayer* layer, const GrTextureDesc& desc, bool dontAtlas);
202 
203     // Inform the cache that layer's cached image is not currently required
204     void unlock(GrCachedLayer* layer);
205 
206     // Setup to be notified when 'picture' is deleted
207     void trackPicture(const SkPicture* picture);
208 
209     // Cleanup after any SkPicture deletions
210     void processDeletedPictures();
211 
212     SkDEBUGCODE(void validate() const;)
213 
214 private:
215     static const int kAtlasTextureWidth = 1024;
216     static const int kAtlasTextureHeight = 1024;
217 
218     static const int kNumPlotsX = 2;
219     static const int kNumPlotsY = 2;
220 
221     static const int kPlotWidth = kAtlasTextureWidth / kNumPlotsX;
222     static const int kPlotHeight = kAtlasTextureHeight / kNumPlotsY;
223 
224     GrContext*                fContext;  // pointer back to owning context
225     SkAutoTDelete<GrAtlas>    fAtlas;    // TODO: could lazily allocate
226 
227     // We cache this information here (rather then, say, on the owning picture)
228     // because we want to be able to clean it up as needed (e.g., if a picture
229     // is leaked and never cleans itself up we still want to be able to
230     // remove the GrPictureInfo once its layers are purged from all the atlas
231     // plots).
232     SkTDynamicHash<GrPictureInfo, uint32_t> fPictureHash;
233 
234     SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key> fLayerHash;
235 
236     SkMessageBus<GrPictureDeletedMessage>::Inbox fPictDeletionInbox;
237 
238     SkAutoTUnref<SkPicture::DeletionListener> fDeletionListener;
239 
240     // This implements a plot-centric locking mechanism (since the atlas
241     // backing texture is always locked). Each layer that is locked (i.e.,
242     // needed for the current rendering) in a plot increments the plot lock
243     // count for that plot. Similarly, once a rendering is complete all the
244     // layers used in it decrement the lock count for the used plots.
245     // Plots with a 0 lock count are open for recycling/purging.
246     int fPlotLocks[kNumPlotsX * kNumPlotsY];
247 
248     void initAtlas();
249     GrCachedLayer* createLayer(uint32_t pictureID, int start, int stop,
250                                const SkIPoint& offset, const SkMatrix& ctm,
251                                const SkPaint* paint);
252 
253     void purgeAll();
254 
255     // Remove all the layers (and unlock any resources) associated with 'pictureID'
256     void purge(uint32_t pictureID);
257 
PlausiblyAtlasable(int width,int height)258     static bool PlausiblyAtlasable(int width, int height) {
259         return width <= kPlotWidth && height <= kPlotHeight;
260     }
261 
262     void purgePlot(GrPlot* plot);
263 
264     // Try to find a purgeable plot and clear it out. Return true if a plot
265     // was purged; false otherwise.
266     bool purgePlot();
267 
268     // for testing
269     friend class TestingAccess;
numLayers()270     int numLayers() const { return fLayerHash.count(); }
271 };
272 
273 #endif
274