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 GrBatchAtlas_DEFINED
9 #define GrBatchAtlas_DEFINED
10 
11 #include "GrTexture.h"
12 #include "SkPoint.h"
13 #include "SkTDArray.h"
14 #include "SkTInternalLList.h"
15 
16 class BatchPlot;
17 class GrBatchTarget;
18 class GrRectanizer;
19 
20 typedef SkTInternalLList<BatchPlot> GrBatchPlotList;
21 
22 class GrBatchAtlas {
23 public:
24     typedef uint64_t BatchToken;
25     // An AtlasID is an opaque handle which callers can use to determine if the atlas contains
26     // a specific piece of data
27     typedef uint32_t AtlasID;
28     static const uint32_t kInvalidAtlasID = 0;
29     static const uint64_t kInvalidAtlasGeneration = 0;
30 
31     // A function pointer for use as a callback during eviction.  Whenever GrBatchAtlas evicts a
32     // specific AtlasID, it will call all of the registered listeners so they can optionally process
33     // the eviction
34     typedef void (*EvictionFunc)(GrBatchAtlas::AtlasID, void*);
35 
36     GrBatchAtlas(GrTexture*, int numPlotsX, int numPlotsY);
37     ~GrBatchAtlas();
38 
39     // Adds a width x height subimage to the atlas. Upon success it returns
40     // the containing GrPlot and absolute location in the backing texture.
41     // NULL is returned if the subimage cannot fit in the atlas.
42     // If provided, the image data will be written to the CPU-side backing bitmap.
43     // NOTE: If the client intends to refer to the atlas, they should immediately call 'setUseToken'
44     // with the currentToken from the batch target, otherwise the next call to addToAtlas might
45     // cause an eviction
46     bool addToAtlas(AtlasID*, GrBatchTarget*, int width, int height, const void* image,
47                     SkIPoint16* loc);
48 
getTexture()49     GrTexture* getTexture() const { return fTexture; }
50 
atlasGeneration()51     uint64_t atlasGeneration() const { return fAtlasGeneration; }
52     bool hasID(AtlasID id);
53 
54     // To ensure the atlas does not evict a given entry, the client must set the last use token
55     void setLastUseToken(AtlasID id, BatchToken batchToken);
registerEvictionCallback(EvictionFunc func,void * userData)56     void registerEvictionCallback(EvictionFunc func, void* userData) {
57         EvictionData* data = fEvictionCallbacks.append();
58         data->fFunc = func;
59         data->fData = userData;
60     }
61 
62     /*
63      * A class which can be handed back to GrBatchAtlas for updating in bulk last use tokens.  The
64      * current max number of plots the GrBatchAtlas can handle is 32, if in the future this is
65      * insufficient then we can move to a 64 bit int
66      */
67     class BulkUseTokenUpdater {
68     public:
BulkUseTokenUpdater()69         BulkUseTokenUpdater() : fPlotAlreadyUpdated(0) {}
add(AtlasID id)70         void add(AtlasID id) {
71             int index = GrBatchAtlas::GetIndexFromID(id);
72             if (!this->find(index)) {
73                 this->set(index);
74             }
75         }
76 
reset()77         void reset() {
78             fPlotsToUpdate.reset();
79             fPlotAlreadyUpdated = 0;
80         }
81 
82     private:
find(int index)83         bool find(int index) const {
84             SkASSERT(index < kMaxPlots);
85             return (fPlotAlreadyUpdated >> index) & 1;
86         }
87 
set(int index)88         void set(int index) {
89             SkASSERT(!this->find(index));
90             fPlotAlreadyUpdated = fPlotAlreadyUpdated | (1 << index);
91             fPlotsToUpdate.push_back(index);
92         }
93 
94         static const int kMinItems = 4;
95         static const int kMaxPlots = 32;
96         SkSTArray<kMinItems, int, true> fPlotsToUpdate;
97         uint32_t fPlotAlreadyUpdated;
98 
99         friend class GrBatchAtlas;
100     };
101 
102     void setLastUseTokenBulk(const BulkUseTokenUpdater& reffer, BatchToken);
103 
104     static const int kGlyphMaxDim = 256;
GlyphTooLargeForAtlas(int width,int height)105     static bool GlyphTooLargeForAtlas(int width, int height) {
106         return width > kGlyphMaxDim || height > kGlyphMaxDim;
107     }
108 
109 private:
GetIndexFromID(AtlasID id)110     static int GetIndexFromID(AtlasID id) {
111         return id & 0xffff;
112     }
113 
GetGenerationFromID(AtlasID id)114     static int GetGenerationFromID(AtlasID id) {
115         return (id >> 16) & 0xffff;
116     }
117 
118     inline void updatePlot(GrBatchTarget*, AtlasID*, BatchPlot*);
119 
120     inline void makeMRU(BatchPlot* plot);
121 
122     inline void processEviction(AtlasID);
123 
124     GrTexture* fTexture;
125     int fNumPlotsX;
126     int fNumPlotsY;
127     int fPlotWidth;
128     int fPlotHeight;
129     size_t fBPP;
130     uint64_t fAtlasGeneration;
131 
132     struct EvictionData {
133         EvictionFunc fFunc;
134         void* fData;
135     };
136 
137     SkTDArray<EvictionData> fEvictionCallbacks;
138     // allocated array of GrBatchPlots
139     SkAutoTUnref<BatchPlot>* fPlotArray;
140     // LRU list of GrPlots (MRU at head - LRU at tail)
141     GrBatchPlotList fPlotList;
142 };
143 
144 #endif
145