OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2010 Google Inc. | 3 * Copyright 2010 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrAtlas.h" | 9 #include "GrAtlas.h" |
10 #include "GrContext.h" | 10 #include "GrContext.h" |
(...skipping 17 matching lines...) Expand all Loading... |
28 #define GR_ATLAS_WIDTH 256 | 28 #define GR_ATLAS_WIDTH 256 |
29 #define GR_ATLAS_HEIGHT 256 | 29 #define GR_ATLAS_HEIGHT 256 |
30 | 30 |
31 #define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH) | 31 #define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH) |
32 #define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT) | 32 #define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT) |
33 | 33 |
34 #endif | 34 #endif |
35 | 35 |
36 /////////////////////////////////////////////////////////////////////////////// | 36 /////////////////////////////////////////////////////////////////////////////// |
37 | 37 |
38 #ifdef SK_DEBUG | |
39 static int gCounter; | |
40 #endif | |
41 | |
42 // for testing | 38 // for testing |
43 #define FONT_CACHE_STATS 0 | 39 #define FONT_CACHE_STATS 0 |
44 #if FONT_CACHE_STATS | 40 #if FONT_CACHE_STATS |
45 static int g_UploadCount = 0; | 41 static int g_UploadCount = 0; |
46 #endif | 42 #endif |
47 | 43 |
48 GrPlot::GrPlot() : fDrawToken(NULL, 0) | 44 GrPlot::GrPlot() : fDrawToken(NULL, 0) |
49 , fNext(NULL) | |
50 , fTexture(NULL) | 45 , fTexture(NULL) |
51 , fAtlasMgr(NULL) | 46 , fAtlasMgr(NULL) |
52 , fBytesPerPixel(1) | 47 , fBytesPerPixel(1) |
53 { | 48 { |
54 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH, | 49 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH, |
55 GR_ATLAS_HEIGHT); | 50 GR_ATLAS_HEIGHT); |
56 fOffset.set(0, 0); | 51 fOffset.set(0, 0); |
57 } | 52 } |
58 | 53 |
59 GrPlot::~GrPlot() { | 54 GrPlot::~GrPlot() { |
(...skipping 27 matching lines...) Expand all Loading... |
87 fTexture->config(), image, 0, | 82 fTexture->config(), image, 0, |
88 GrContext::kDontFlush_PixelOpsFlag); | 83 GrContext::kDontFlush_PixelOpsFlag); |
89 | 84 |
90 #if FONT_CACHE_STATS | 85 #if FONT_CACHE_STATS |
91 ++g_UploadCount; | 86 ++g_UploadCount; |
92 #endif | 87 #endif |
93 | 88 |
94 return true; | 89 return true; |
95 } | 90 } |
96 | 91 |
| 92 void GrPlot::resetRects() { |
| 93 SkASSERT(NULL != fRects); |
| 94 fRects->reset(); |
| 95 } |
| 96 |
97 /////////////////////////////////////////////////////////////////////////////// | 97 /////////////////////////////////////////////////////////////////////////////// |
98 | 98 |
99 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) { | 99 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) { |
100 fGpu = gpu; | 100 fGpu = gpu; |
101 fPixelConfig = config; | 101 fPixelConfig = config; |
102 gpu->ref(); | 102 gpu->ref(); |
103 fTexture = NULL; | 103 fTexture = NULL; |
104 | 104 |
105 // set up allocated plots | 105 // set up allocated plots |
106 size_t bpp = GrBytesPerPixel(fPixelConfig); | 106 size_t bpp = GrBytesPerPixel(fPixelConfig); |
107 fPlots = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT)); | 107 fPlotArray = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT)); |
108 fFreePlots = NULL; | 108 |
109 GrPlot* currPlot = fPlots; | 109 GrPlot* currPlot = fPlotArray; |
110 for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) { | 110 for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) { |
111 for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) { | 111 for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) { |
112 currPlot->fAtlasMgr = this; | 112 currPlot->fAtlasMgr = this; |
113 currPlot->fOffset.set(x, y); | 113 currPlot->fOffset.set(x, y); |
114 currPlot->fBytesPerPixel = bpp; | 114 currPlot->fBytesPerPixel = bpp; |
115 | 115 |
116 // add to free list | 116 // build LRU list |
117 currPlot->fNext = fFreePlots; | 117 fPlotList.addToHead(currPlot); |
118 fFreePlots = currPlot; | |
119 | |
120 ++currPlot; | 118 ++currPlot; |
121 } | 119 } |
122 } | 120 } |
123 } | 121 } |
124 | 122 |
125 GrAtlasMgr::~GrAtlasMgr() { | 123 GrAtlasMgr::~GrAtlasMgr() { |
126 SkSafeUnref(fTexture); | 124 SkSafeUnref(fTexture); |
127 SkDELETE_ARRAY(fPlots); | 125 SkDELETE_ARRAY(fPlotArray); |
128 | 126 |
129 fGpu->unref(); | 127 fGpu->unref(); |
130 #if FONT_CACHE_STATS | 128 #if FONT_CACHE_STATS |
131 GrPrintf("Num uploads: %d\n", g_UploadCount); | 129 GrPrintf("Num uploads: %d\n", g_UploadCount); |
132 #endif | 130 #endif |
133 } | 131 } |
134 | 132 |
| 133 void GrAtlasMgr::moveToHead(GrPlot* plot) { |
| 134 if (fPlotList.head() == plot) { |
| 135 return; |
| 136 } |
| 137 |
| 138 fPlotList.remove(plot); |
| 139 fPlotList.addToHead(plot); |
| 140 }; |
| 141 |
135 GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas, | 142 GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas, |
136 int width, int height, const void* image, | 143 int width, int height, const void* image, |
137 GrIPoint16* loc) { | 144 GrIPoint16* loc) { |
138 // iterate through entire plot list, see if we can find a hole | 145 // iterate through entire plot list for this atlas, see if we can find a hol
e |
139 GrPlot* plotIter = atlas->fPlots; | 146 // last one was most recently added and probably most empty |
140 while (plotIter) { | 147 for (int i = atlas->fPlots.count()-1; i >= 0; --i) { |
141 if (plotIter->addSubImage(width, height, image, loc)) { | 148 GrPlot* plot = atlas->fPlots[i]; |
142 return plotIter; | 149 if (plot->addSubImage(width, height, image, loc)) { |
| 150 this->moveToHead(plot); |
| 151 return plot; |
143 } | 152 } |
144 plotIter = plotIter->fNext; | |
145 } | 153 } |
146 | 154 |
147 // If the above fails, then either we have no starting plot, or the current | 155 // before we get a new plot, make sure we have a backing texture |
148 // plot list is full. Either way we need to allocate a new plot | |
149 GrPlot* newPlot = this->allocPlot(); | |
150 if (NULL == newPlot) { | |
151 return NULL; | |
152 } | |
153 | |
154 if (NULL == fTexture) { | 156 if (NULL == fTexture) { |
155 // TODO: Update this to use the cache rather than directly creating a te
xture. | 157 // TODO: Update this to use the cache rather than directly creating a te
xture. |
156 GrTextureDesc desc; | 158 GrTextureDesc desc; |
157 desc.fFlags = kDynamicUpdate_GrTextureFlagBit; | 159 desc.fFlags = kDynamicUpdate_GrTextureFlagBit; |
158 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH; | 160 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH; |
159 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT; | 161 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT; |
160 desc.fConfig = fPixelConfig; | 162 desc.fConfig = fPixelConfig; |
161 | 163 |
162 fTexture = fGpu->createTexture(desc, NULL, 0); | 164 fTexture = fGpu->createTexture(desc, NULL, 0); |
163 if (NULL == fTexture) { | 165 if (NULL == fTexture) { |
164 return NULL; | 166 return NULL; |
165 } | 167 } |
166 } | 168 } |
167 // be sure to set texture for fast lookup | |
168 newPlot->fTexture = fTexture; | |
169 | 169 |
170 if (!newPlot->addSubImage(width, height, image, loc)) { | 170 // now look through all allocated plots for one we can share, in MRU order |
171 this->freePlot(newPlot); | 171 GrPlotList::Iter plotIter; |
172 return NULL; | 172 plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart); |
| 173 GrPlot* plot; |
| 174 while (NULL != (plot = plotIter.get())) { |
| 175 // make sure texture is set for quick lookup |
| 176 plot->fTexture = fTexture; |
| 177 if (plot->addSubImage(width, height, image, loc)) { |
| 178 this->moveToHead(plot); |
| 179 // new plot for atlas, put at end of array |
| 180 *(atlas->fPlots.append()) = plot; |
| 181 return plot; |
| 182 } |
| 183 plotIter.next(); |
173 } | 184 } |
174 | 185 |
175 // new plot, put at head | 186 // If the above fails, then the current plot list has no room |
176 newPlot->fNext = atlas->fPlots; | 187 return NULL; |
177 atlas->fPlots = newPlot; | |
178 | |
179 return newPlot; | |
180 } | 188 } |
181 | 189 |
182 bool GrAtlasMgr::removeUnusedPlots(GrAtlas* atlas) { | 190 bool GrAtlasMgr::removePlot(GrAtlas* atlas, const GrPlot* plot) { |
183 | 191 // iterate through plot list for this atlas |
184 // GrPlot** is used so that the head element can be easily | 192 int count = atlas->fPlots.count(); |
185 // modified when the first element is deleted | 193 for (int i = 0; i < count; ++i) { |
186 GrPlot** plotRef = &atlas->fPlots; | 194 if (plot == atlas->fPlots[i]) { |
187 GrPlot* plot = atlas->fPlots; | 195 atlas->fPlots.remove(i); |
188 bool removed = false; | 196 return true; |
189 while (NULL != plot) { | |
190 if (plot->drawToken().isIssued()) { | |
191 *plotRef = plot->fNext; | |
192 this->freePlot(plot); | |
193 plot = *plotRef; | |
194 removed = true; | |
195 } else { | |
196 plotRef = &plot->fNext; | |
197 plot = plot->fNext; | |
198 } | 197 } |
199 } | 198 } |
200 | 199 |
201 return removed; | 200 return false; |
202 } | 201 } |
203 | 202 |
204 void GrAtlasMgr::deletePlotList(GrPlot* plot) { | 203 // get a plot that's not being used by the current draw |
205 while (NULL != plot) { | 204 GrPlot* GrAtlasMgr::getUnusedPlot() { |
206 GrPlot* next = plot->fNext; | 205 GrPlotList::Iter plotIter; |
207 this->freePlot(plot); | 206 plotIter.init(fPlotList, GrPlotList::Iter::kTail_IterStart); |
208 plot = next; | 207 GrPlot* plot; |
209 } | 208 while (NULL != (plot = plotIter.get())) { |
210 } | 209 if (plot->drawToken().isIssued()) { |
211 | 210 return plot; |
212 GrPlot* GrAtlasMgr::allocPlot() { | 211 } |
213 if (NULL == fFreePlots) { | 212 plotIter.prev(); |
214 return NULL; | |
215 } else { | |
216 GrPlot* alloc = fFreePlots; | |
217 fFreePlots = alloc->fNext; | |
218 #ifdef SK_DEBUG | |
219 // GrPrintf(" GrPlot %p [%d %d] %d\n", this, alloc->fOffset.fX, alloc->fO
ffset.fY, gCounter); | |
220 gCounter += 1; | |
221 #endif | |
222 return alloc; | |
223 } | 213 } |
224 | 214 |
225 } | 215 return NULL; |
226 | |
227 void GrAtlasMgr::freePlot(GrPlot* plot) { | |
228 SkASSERT(this == plot->fAtlasMgr); | |
229 | |
230 plot->fRects->reset(); | |
231 plot->fNext = fFreePlots; | |
232 fFreePlots = plot; | |
233 | |
234 #ifdef SK_DEBUG | |
235 --gCounter; | |
236 // GrPrintf("~GrPlot %p [%d %d] %d\n", this, plot->fOffset.fX, plot->fOffset.
fY, gCounter); | |
237 #endif | |
238 } | 216 } |
239 | 217 |
240 SkISize GrAtlas::getSize() const { | 218 SkISize GrAtlas::getSize() const { |
241 return SkISize::Make(GR_ATLAS_TEXTURE_WIDTH, GR_ATLAS_TEXTURE_HEIGHT); | 219 return SkISize::Make(GR_ATLAS_TEXTURE_WIDTH, GR_ATLAS_TEXTURE_HEIGHT); |
242 } | 220 } |
OLD | NEW |