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 | |
10 | |
11 #include "GrAtlas.h" | 9 #include "GrAtlas.h" |
12 #include "GrContext.h" | 10 #include "GrContext.h" |
13 #include "GrGpu.h" | 11 #include "GrGpu.h" |
14 #include "GrRectanizer.h" | 12 #include "GrRectanizer.h" |
15 #include "GrPlotMgr.h" | |
16 | 13 |
17 #if 0 | 14 #if 0 |
18 #define GR_PLOT_WIDTH 8 | 15 #define GR_PLOT_WIDTH 8 |
19 #define GR_PLOT_HEIGHT 4 | 16 #define GR_PLOT_HEIGHT 4 |
20 #define GR_ATLAS_WIDTH 256 | 17 #define GR_ATLAS_WIDTH 256 |
21 #define GR_ATLAS_HEIGHT 256 | 18 #define GR_ATLAS_HEIGHT 256 |
22 | 19 |
23 #define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH) | 20 #define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH) |
24 #define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT) | 21 #define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT) |
25 | 22 |
(...skipping 17 matching lines...) Expand all Loading... |
43 #ifdef SK_DEBUG | 40 #ifdef SK_DEBUG |
44 static int gCounter; | 41 static int gCounter; |
45 #endif | 42 #endif |
46 | 43 |
47 // for testing | 44 // for testing |
48 #define FONT_CACHE_STATS 0 | 45 #define FONT_CACHE_STATS 0 |
49 #if FONT_CACHE_STATS | 46 #if FONT_CACHE_STATS |
50 static int g_UploadCount = 0; | 47 static int g_UploadCount = 0; |
51 #endif | 48 #endif |
52 | 49 |
53 GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, int bpp) : | 50 GrPlot::GrPlot() : fDrawToken(NULL, 0) |
54 fDrawToken(NULL, 0) { | 51 , fNext(NULL) |
55 fAtlasMgr = mgr; // just a pointer, not an owner | 52 , fTexture(NULL) |
56 fNext = NULL; | 53 , fAtlasMgr(NULL) |
57 | 54 , fBytesPerPixel(1) |
58 fTexture = mgr->getTexture(); // we're not an owner, just a pointer | 55 { |
59 fPlot.set(plotX, plotY); | |
60 | |
61 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER, | 56 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER, |
62 GR_ATLAS_HEIGHT - BORDER); | 57 GR_ATLAS_HEIGHT - BORDER); |
63 | 58 fOffset.set(0, 0); |
64 fBytesPerPixel = bpp; | |
65 | |
66 #ifdef SK_DEBUG | |
67 // GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter); | |
68 gCounter += 1; | |
69 #endif | |
70 } | 59 } |
71 | 60 |
72 GrAtlas::~GrAtlas() { | 61 GrPlot::~GrPlot() { |
73 fAtlasMgr->freePlot(fPlot.fX, fPlot.fY); | |
74 | |
75 delete fRects; | 62 delete fRects; |
76 | |
77 #ifdef SK_DEBUG | |
78 --gCounter; | |
79 // GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter); | |
80 #endif | |
81 } | 63 } |
82 | 64 |
83 bool GrAtlas::RemoveUnusedAtlases(GrAtlasMgr* atlasMgr, GrAtlas** startAtlas) { | 65 static void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) { |
84 // GrAtlas** is used so that a pointer to the head element can be passed in
and | 66 loc->fX += offset.fX * GR_ATLAS_WIDTH; |
85 // modified when the first element is deleted | 67 loc->fY += offset.fY * GR_ATLAS_HEIGHT; |
86 GrAtlas** atlasRef = startAtlas; | |
87 GrAtlas* atlas = *startAtlas; | |
88 bool removed = false; | |
89 while (NULL != atlas) { | |
90 if (atlas->drawToken().isIssued()) { | |
91 *atlasRef = atlas->fNext; | |
92 atlasMgr->deleteAtlas(atlas); | |
93 atlas = *atlasRef; | |
94 removed = true; | |
95 } else { | |
96 atlasRef = &atlas->fNext; | |
97 atlas = atlas->fNext; | |
98 } | |
99 } | |
100 | |
101 return removed; | |
102 } | 68 } |
103 | 69 |
104 static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) { | 70 static uint8_t* zero_fill(uint8_t* ptr, int count) { |
105 loc->fX += plot.fX * GR_ATLAS_WIDTH; | |
106 loc->fY += plot.fY * GR_ATLAS_HEIGHT; | |
107 } | |
108 | |
109 static uint8_t* zerofill(uint8_t* ptr, int count) { | |
110 while (--count >= 0) { | 71 while (--count >= 0) { |
111 *ptr++ = 0; | 72 *ptr++ = 0; |
112 } | 73 } |
113 return ptr; | 74 return ptr; |
114 } | 75 } |
115 | 76 |
116 bool GrAtlas::addSubImage(int width, int height, const void* image, | 77 bool GrPlot::addSubImage(int width, int height, const void* image, |
117 GrIPoint16* loc) { | 78 GrIPoint16* loc) { |
118 if (!fRects->addRect(width + BORDER, height + BORDER, loc)) { | 79 if (!fRects->addRect(width + BORDER, height + BORDER, loc)) { |
119 return false; | 80 return false; |
120 } | 81 } |
121 | 82 |
122 SkAutoSMalloc<1024> storage; | 83 SkAutoSMalloc<1024> storage; |
123 int dstW = width + 2*BORDER; | 84 int dstW = width + 2*BORDER; |
124 int dstH = height + 2*BORDER; | 85 int dstH = height + 2*BORDER; |
125 if (BORDER) { | 86 if (BORDER) { |
126 const size_t dstRB = dstW * fBytesPerPixel; | 87 const size_t dstRB = dstW * fBytesPerPixel; |
127 uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB); | 88 uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB); |
128 sk_bzero(dst, dstRB); // zero top row | 89 sk_bzero(dst, dstRB); // zero top row |
129 dst += dstRB; | 90 dst += dstRB; |
130 for (int y = 0; y < height; y++) { | 91 for (int y = 0; y < height; y++) { |
131 dst = zerofill(dst, fBytesPerPixel); // zero left edge | 92 dst = zero_fill(dst, fBytesPerPixel); // zero left edge |
132 memcpy(dst, image, width * fBytesPerPixel); | 93 memcpy(dst, image, width * fBytesPerPixel); |
133 dst += width * fBytesPerPixel; | 94 dst += width * fBytesPerPixel; |
134 dst = zerofill(dst, fBytesPerPixel); // zero right edge | 95 dst = zero_fill(dst, fBytesPerPixel); // zero right edge |
135 image = (const void*)((const char*)image + width * fBytesPerPixel); | 96 image = (const void*)((const char*)image + width * fBytesPerPixel); |
136 } | 97 } |
137 sk_bzero(dst, dstRB); // zero bottom row | 98 sk_bzero(dst, dstRB); // zero bottom row |
138 image = storage.get(); | 99 image = storage.get(); |
139 } | 100 } |
140 adjustForPlot(loc, fPlot); | 101 adjust_for_offset(loc, fOffset); |
141 GrContext* context = fTexture->getContext(); | 102 GrContext* context = fTexture->getContext(); |
142 // We pass the flag that does not force a flush. We assume our caller is | 103 // We pass the flag that does not force a flush. We assume our caller is |
143 // smart and hasn't referenced the part of the texture we're about to update | 104 // smart and hasn't referenced the part of the texture we're about to update |
144 // since the last flush. | 105 // since the last flush. |
145 context->writeTexturePixels(fTexture, | 106 context->writeTexturePixels(fTexture, |
146 loc->fX, loc->fY, dstW, dstH, | 107 loc->fX, loc->fY, dstW, dstH, |
147 fTexture->config(), image, 0, | 108 fTexture->config(), image, 0, |
148 GrContext::kDontFlush_PixelOpsFlag); | 109 GrContext::kDontFlush_PixelOpsFlag); |
149 | 110 |
150 // now tell the caller to skip the top/left BORDER | 111 // now tell the caller to skip the top/left BORDER |
151 loc->fX += BORDER; | 112 loc->fX += BORDER; |
152 loc->fY += BORDER; | 113 loc->fY += BORDER; |
153 | 114 |
154 #if FONT_CACHE_STATS | 115 #if FONT_CACHE_STATS |
155 ++g_UploadCount; | 116 ++g_UploadCount; |
156 #endif | 117 #endif |
157 | 118 |
158 return true; | 119 return true; |
159 } | 120 } |
160 | 121 |
161 /////////////////////////////////////////////////////////////////////////////// | 122 /////////////////////////////////////////////////////////////////////////////// |
162 | 123 |
163 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) { | 124 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) { |
164 fGpu = gpu; | 125 fGpu = gpu; |
165 fPixelConfig = config; | 126 fPixelConfig = config; |
166 gpu->ref(); | 127 gpu->ref(); |
167 fTexture = NULL; | 128 fTexture = NULL; |
168 fPlotMgr = SkNEW_ARGS(GrPlotMgr, (GR_PLOT_WIDTH, GR_PLOT_HEIGHT)); | 129 |
| 130 // set up allocated plots |
| 131 int bpp = GrBytesPerPixel(fPixelConfig); |
| 132 fPlots = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT)); |
| 133 fFreePlots = NULL; |
| 134 GrPlot* currPlot = fPlots; |
| 135 for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) { |
| 136 for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) { |
| 137 currPlot->fAtlasMgr = this; |
| 138 currPlot->fOffset.set(x, y); |
| 139 currPlot->fBytesPerPixel = bpp; |
| 140 |
| 141 // add to free list |
| 142 currPlot->fNext = fFreePlots; |
| 143 fFreePlots = currPlot; |
| 144 |
| 145 ++currPlot; |
| 146 } |
| 147 } |
169 } | 148 } |
170 | 149 |
171 GrAtlasMgr::~GrAtlasMgr() { | 150 GrAtlasMgr::~GrAtlasMgr() { |
172 SkSafeUnref(fTexture); | 151 SkSafeUnref(fTexture); |
173 delete fPlotMgr; | 152 SkDELETE_ARRAY(fPlots); |
174 | 153 |
175 fGpu->unref(); | 154 fGpu->unref(); |
176 #if FONT_CACHE_STATS | 155 #if FONT_CACHE_STATS |
177 GrPrintf("Num uploads: %d\n", g_UploadCount); | 156 GrPrintf("Num uploads: %d\n", g_UploadCount); |
178 #endif | 157 #endif |
179 } | 158 } |
180 | 159 |
181 GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas** atlas, | 160 GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas, |
182 int width, int height, const void* image, | 161 int width, int height, const void* image, |
183 GrIPoint16* loc) { | 162 GrIPoint16* loc) { |
184 // iterate through entire atlas list, see if we can find a hole | 163 // iterate through entire plot list, see if we can find a hole |
185 GrAtlas* atlasIter = *atlas; | 164 GrPlot* plotIter = atlas->fPlots; |
186 while (atlasIter) { | 165 while (plotIter) { |
187 if (atlasIter->addSubImage(width, height, image, loc)) { | 166 if (plotIter->addSubImage(width, height, image, loc)) { |
188 return atlasIter; | 167 return plotIter; |
189 } | 168 } |
190 atlasIter = atlasIter->fNext; | 169 plotIter = plotIter->fNext; |
191 } | 170 } |
192 | 171 |
193 // If the above fails, then either we have no starting atlas, or the current | 172 // If the above fails, then either we have no starting plot, or the current |
194 // atlas list is full. Either way we need to allocate a new atlas | 173 // plot list is full. Either way we need to allocate a new plot |
195 | 174 GrPlot* newPlot = this->allocPlot(); |
196 GrIPoint16 plot; | 175 if (NULL == newPlot) { |
197 if (!fPlotMgr->newPlot(&plot)) { | |
198 return NULL; | 176 return NULL; |
199 } | 177 } |
200 | 178 |
201 if (NULL == fTexture) { | 179 if (NULL == fTexture) { |
202 // TODO: Update this to use the cache rather than directly creating a te
xture. | 180 // TODO: Update this to use the cache rather than directly creating a te
xture. |
203 GrTextureDesc desc; | 181 GrTextureDesc desc; |
204 desc.fFlags = kDynamicUpdate_GrTextureFlagBit; | 182 desc.fFlags = kDynamicUpdate_GrTextureFlagBit; |
205 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH; | 183 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH; |
206 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT; | 184 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT; |
207 desc.fConfig = fPixelConfig; | 185 desc.fConfig = fPixelConfig; |
208 | 186 |
209 fTexture = fGpu->createTexture(desc, NULL, 0); | 187 fTexture = fGpu->createTexture(desc, NULL, 0); |
210 if (NULL == fTexture) { | 188 if (NULL == fTexture) { |
211 return NULL; | 189 return NULL; |
212 } | 190 } |
213 } | 191 } |
214 | 192 // be sure to set texture for fast lookup |
215 int bpp = GrBytesPerPixel(fPixelConfig); | 193 newPlot->fTexture = fTexture; |
216 GrAtlas* newAtlas = SkNEW_ARGS(GrAtlas, (this, plot.fX, plot.fY, bpp)); | 194 |
217 if (!newAtlas->addSubImage(width, height, image, loc)) { | 195 if (!newPlot->addSubImage(width, height, image, loc)) { |
218 delete newAtlas; | 196 this->freePlot(newPlot); |
219 return NULL; | 197 return NULL; |
220 } | 198 } |
221 | 199 |
222 // new atlas, put at head | 200 // new plot, put at head |
223 newAtlas->fNext = *atlas; | 201 newPlot->fNext = atlas->fPlots; |
224 *atlas = newAtlas; | 202 atlas->fPlots = newPlot; |
225 | 203 |
226 return newAtlas; | 204 return newPlot; |
227 } | 205 } |
228 | 206 |
229 void GrAtlasMgr::freePlot(int x, int y) { | 207 bool GrAtlasMgr::removeUnusedPlots(GrAtlas* atlas) { |
230 SkASSERT(fPlotMgr->isBusy(x, y)); | 208 // GrPlot** is used so that the head element can be easily |
231 fPlotMgr->freePlot(x, y); | 209 // modified when the first element is deleted |
| 210 GrPlot** plotRef = &atlas->fPlots; |
| 211 GrPlot* plot = atlas->fPlots; |
| 212 bool removed = false; |
| 213 while (NULL != plot) { |
| 214 if (plot->drawToken().isIssued()) { |
| 215 *plotRef = plot->fNext; |
| 216 this->freePlot(plot); |
| 217 plot = *plotRef; |
| 218 removed = true; |
| 219 } else { |
| 220 plotRef = &plot->fNext; |
| 221 plot = plot->fNext; |
| 222 } |
| 223 } |
| 224 |
| 225 return removed; |
232 } | 226 } |
| 227 |
| 228 void GrAtlasMgr::deletePlotList(GrPlot* plot) { |
| 229 while (NULL != plot) { |
| 230 GrPlot* next = plot->fNext; |
| 231 this->freePlot(plot); |
| 232 plot = next; |
| 233 } |
| 234 } |
| 235 |
| 236 GrPlot* GrAtlasMgr::allocPlot() { |
| 237 if (NULL == fFreePlots) { |
| 238 return NULL; |
| 239 } else { |
| 240 GrPlot* alloc = fFreePlots; |
| 241 fFreePlots = alloc->fNext; |
| 242 #ifdef SK_DEBUG |
| 243 // GrPrintf(" GrPlot %p [%d %d] %d\n", this, alloc->fOffset.fX, alloc->fO
ffset.fY, gCounter); |
| 244 gCounter += 1; |
| 245 #endif |
| 246 return alloc; |
| 247 } |
| 248 |
| 249 } |
| 250 |
| 251 void GrAtlasMgr::freePlot(GrPlot* plot) { |
| 252 SkASSERT(this == plot->fAtlasMgr); |
| 253 |
| 254 plot->fRects->reset(); |
| 255 plot->fNext = fFreePlots; |
| 256 fFreePlots = plot; |
| 257 |
| 258 #ifdef SK_DEBUG |
| 259 --gCounter; |
| 260 // GrPrintf("~GrPlot %p [%d %d] %d\n", this, plot->fOffset.fX, plot->fOffset.
fY, gCounter); |
| 261 #endif |
| 262 } |
OLD | NEW |