1 2 /* 3 * Copyright 2010 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 11 #include "GrAtlas.h" 12 #include "GrContext.h" 13 #include "GrGpu.h" 14 #include "GrRectanizer.h" 15 #include "GrPlotMgr.h" 16 17 #if 0 18 #define GR_PLOT_WIDTH 8 19 #define GR_PLOT_HEIGHT 4 20 #define GR_ATLAS_WIDTH 256 21 #define GR_ATLAS_HEIGHT 256 22 23 #define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH) 24 #define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT) 25 26 #else 27 28 #define GR_ATLAS_TEXTURE_WIDTH 1024 29 #define GR_ATLAS_TEXTURE_HEIGHT 2048 30 31 #define GR_ATLAS_WIDTH 341 32 #define GR_ATLAS_HEIGHT 341 33 34 #define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH) 35 #define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT) 36 37 #endif 38 39 /////////////////////////////////////////////////////////////////////////////// 40 41 #define BORDER 1 42 43 #if GR_DEBUG 44 static int gCounter; 45 #endif 46 47 // for testing 48 #define FONT_CACHE_STATS 0 49 #if FONT_CACHE_STATS 50 static int g_UploadCount = 0; 51 #endif 52 53 GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) { 54 fAtlasMgr = mgr; // just a pointer, not an owner 55 fNext = NULL; 56 fUsed = false; 57 58 fTexture = mgr->getTexture(format); // we're not an owner, just a pointer 59 fPlot.set(plotX, plotY); 60 61 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER, 62 GR_ATLAS_HEIGHT - BORDER); 63 64 fMaskFormat = format; 65 66 #if GR_DEBUG 67 // GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter); 68 gCounter += 1; 69 #endif 70 } 71 72 GrAtlas::~GrAtlas() { 73 fAtlasMgr->freePlot(fMaskFormat, fPlot.fX, fPlot.fY); 74 75 delete fRects; 76 77 #if GR_DEBUG 78 --gCounter; 79 // GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter); 80 #endif 81 } 82 83 bool GrAtlas::RemoveUnusedAtlases(GrAtlasMgr* atlasMgr, GrAtlas** startAtlas) { 84 // GrAtlas** is used so that a pointer to the head element can be passed in and 85 // modified when the first element is deleted 86 GrAtlas** atlasRef = startAtlas; 87 GrAtlas* atlas = *startAtlas; 88 bool removed = false; 89 while (NULL != atlas) { 90 if (!atlas->used()) { 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 } 103 104 static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) { 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) { 111 *ptr++ = 0; 112 } 113 return ptr; 114 } 115 116 bool GrAtlas::addSubImage(int width, int height, const void* image, 117 GrIPoint16* loc) { 118 if (!fRects->addRect(width + BORDER, height + BORDER, loc)) { 119 return false; 120 } 121 122 SkAutoSMalloc<1024> storage; 123 int dstW = width + 2*BORDER; 124 int dstH = height + 2*BORDER; 125 if (BORDER) { 126 const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat); 127 const size_t dstRB = dstW * bpp; 128 uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB); 129 Gr_bzero(dst, dstRB); // zero top row 130 dst += dstRB; 131 for (int y = 0; y < height; y++) { 132 dst = zerofill(dst, bpp); // zero left edge 133 memcpy(dst, image, width * bpp); 134 dst += width * bpp; 135 dst = zerofill(dst, bpp); // zero right edge 136 image = (const void*)((const char*)image + width * bpp); 137 } 138 Gr_bzero(dst, dstRB); // zero bottom row 139 image = storage.get(); 140 } 141 adjustForPlot(loc, fPlot); 142 GrContext* context = fTexture->getContext(); 143 // We pass the flag that does not force a flush. We assume our caller is 144 // smart and hasn't referenced the part of the texture we're about to update 145 // since the last flush. 146 context->writeTexturePixels(fTexture, 147 loc->fX, loc->fY, dstW, dstH, 148 fTexture->config(), image, 0, 149 GrContext::kDontFlush_PixelOpsFlag); 150 151 // now tell the caller to skip the top/left BORDER 152 loc->fX += BORDER; 153 loc->fY += BORDER; 154 155 #if FONT_CACHE_STATS 156 ++g_UploadCount; 157 #endif 158 159 return true; 160 } 161 162 /////////////////////////////////////////////////////////////////////////////// 163 164 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu) { 165 fGpu = gpu; 166 gpu->ref(); 167 Gr_bzero(fTexture, sizeof(fTexture)); 168 fPlotMgr = SkNEW_ARGS(GrPlotMgr, (GR_PLOT_WIDTH, GR_PLOT_HEIGHT)); 169 } 170 171 GrAtlasMgr::~GrAtlasMgr() { 172 for (size_t i = 0; i < GR_ARRAY_COUNT(fTexture); i++) { 173 GrSafeUnref(fTexture[i]); 174 } 175 delete fPlotMgr; 176 177 fGpu->unref(); 178 #if FONT_CACHE_STATS 179 GrPrintf("Num uploads: %d\n", g_UploadCount); 180 #endif 181 } 182 183 static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) { 184 switch (format) { 185 case kA8_GrMaskFormat: 186 return kAlpha_8_GrPixelConfig; 187 case kA565_GrMaskFormat: 188 return kRGB_565_GrPixelConfig; 189 case kA888_GrMaskFormat: 190 return kSkia8888_GrPixelConfig; 191 default: 192 GrAssert(!"unknown maskformat"); 193 } 194 return kUnknown_GrPixelConfig; 195 } 196 197 GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas** atlas, 198 int width, int height, const void* image, 199 GrMaskFormat format, 200 GrIPoint16* loc) { 201 GrAssert(NULL == *atlas || (*atlas)->getMaskFormat() == format); 202 203 // iterate through entire atlas list, see if we can find a hole 204 GrAtlas* atlasIter = *atlas; 205 while (atlasIter) { 206 if (atlasIter->addSubImage(width, height, image, loc)) { 207 return atlasIter; 208 } 209 atlasIter = atlasIter->fNext; 210 } 211 212 // If the above fails, then either we have no starting atlas, or the current 213 // atlas list is full. Either way we need to allocate a new atlas 214 215 GrIPoint16 plot; 216 if (!fPlotMgr->newPlot(&plot)) { 217 return NULL; 218 } 219 220 GrAssert(0 == kA8_GrMaskFormat); 221 GrAssert(1 == kA565_GrMaskFormat); 222 if (NULL == fTexture[format]) { 223 // TODO: Update this to use the cache rather than directly creating a texture. 224 GrTextureDesc desc; 225 desc.fFlags = kDynamicUpdate_GrTextureFlagBit; 226 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH; 227 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT; 228 desc.fConfig = maskformat2pixelconfig(format); 229 230 fTexture[format] = fGpu->createTexture(desc, NULL, 0); 231 if (NULL == fTexture[format]) { 232 return NULL; 233 } 234 } 235 236 GrAtlas* newAtlas = SkNEW_ARGS(GrAtlas, (this, plot.fX, plot.fY, format)); 237 if (!newAtlas->addSubImage(width, height, image, loc)) { 238 delete newAtlas; 239 return NULL; 240 } 241 242 // new atlas, put at head 243 newAtlas->fNext = *atlas; 244 *atlas = newAtlas; 245 246 return newAtlas; 247 } 248 249 void GrAtlasMgr::freePlot(GrMaskFormat format, int x, int y) { 250 GrAssert(fPlotMgr->isBusy(x, y)); 251 fPlotMgr->freePlot(x, y); 252 } 253