| 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 |