1 /* 2 Copyright 2010 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 18 #include "GrAtlas.h" 19 #include "GrGpu.h" 20 #include "GrMemory.h" 21 #include "GrRectanizer.h" 22 #include "GrPlotMgr.h" 23 24 #if 0 25 #define GR_PLOT_WIDTH 8 26 #define GR_PLOT_HEIGHT 4 27 #define GR_ATLAS_WIDTH 256 28 #define GR_ATLAS_HEIGHT 256 29 30 #define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH) 31 #define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT) 32 33 #else 34 35 #define GR_ATLAS_TEXTURE_WIDTH 1024 36 #define GR_ATLAS_TEXTURE_HEIGHT 2048 37 38 #define GR_ATLAS_WIDTH 341 39 #define GR_ATLAS_HEIGHT 341 40 41 #define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH) 42 #define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT) 43 44 #endif 45 46 /////////////////////////////////////////////////////////////////////////////// 47 48 #define BORDER 1 49 50 #if GR_DEBUG 51 static int gCounter; 52 #endif 53 54 GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) { 55 fAtlasMgr = mgr; // just a pointer, not an owner 56 fNext = NULL; 57 fTexture = mgr->getTexture(format); // we're not an owner, just a pointer 58 fPlot.set(plotX, plotY); 59 60 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER, 61 GR_ATLAS_HEIGHT - BORDER); 62 63 fMaskFormat = format; 64 65 #if GR_DEBUG 66 GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter); 67 gCounter += 1; 68 #endif 69 } 70 71 GrAtlas::~GrAtlas() { 72 fAtlasMgr->freePlot(fPlot.fX, fPlot.fY); 73 74 delete fRects; 75 76 #if GR_DEBUG 77 --gCounter; 78 GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter); 79 #endif 80 } 81 82 static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) { 83 loc->fX += plot.fX * GR_ATLAS_WIDTH; 84 loc->fY += plot.fY * GR_ATLAS_HEIGHT; 85 } 86 87 static uint8_t* zerofill(uint8_t* ptr, int count) { 88 while (--count >= 0) { 89 *ptr++ = 0; 90 } 91 return ptr; 92 } 93 94 bool GrAtlas::addSubImage(int width, int height, const void* image, 95 GrIPoint16* loc) { 96 if (!fRects->addRect(width + BORDER, height + BORDER, loc)) { 97 return false; 98 } 99 100 GrAutoSMalloc<1024> storage; 101 int dstW = width + 2*BORDER; 102 int dstH = height + 2*BORDER; 103 if (BORDER) { 104 const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat); 105 const size_t dstRB = dstW * bpp; 106 uint8_t* dst = (uint8_t*)storage.realloc(dstH * dstRB); 107 Gr_bzero(dst, dstRB); // zero top row 108 dst += dstRB; 109 for (int y = 0; y < height; y++) { 110 dst = zerofill(dst, bpp); // zero left edge 111 memcpy(dst, image, width * bpp); 112 dst += width * bpp; 113 dst = zerofill(dst, bpp); // zero right edge 114 image = (const void*)((const char*)image + width * bpp); 115 } 116 Gr_bzero(dst, dstRB); // zero bottom row 117 image = storage.get(); 118 } 119 adjustForPlot(loc, fPlot); 120 fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image); 121 122 // now tell the caller to skip the top/left BORDER 123 loc->fX += BORDER; 124 loc->fY += BORDER; 125 return true; 126 } 127 128 /////////////////////////////////////////////////////////////////////////////// 129 130 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu) { 131 fGpu = gpu; 132 gpu->ref(); 133 Gr_bzero(fTexture, sizeof(fTexture)); 134 fPlotMgr = new GrPlotMgr(GR_PLOT_WIDTH, GR_PLOT_HEIGHT); 135 } 136 137 GrAtlasMgr::~GrAtlasMgr() { 138 for (size_t i = 0; i < GR_ARRAY_COUNT(fTexture); i++) { 139 GrSafeUnref(fTexture[i]); 140 } 141 delete fPlotMgr; 142 fGpu->unref(); 143 } 144 145 static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) { 146 switch (format) { 147 case kA8_GrMaskFormat: 148 return kAlpha_8_GrPixelConfig; 149 case kA565_GrMaskFormat: 150 return kRGB_565_GrPixelConfig; 151 default: 152 GrAssert(!"unknown maskformat"); 153 } 154 return kUnknown_GrPixelConfig; 155 } 156 157 GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas, 158 int width, int height, const void* image, 159 GrMaskFormat format, 160 GrIPoint16* loc) { 161 GrAssert(NULL == atlas || atlas->getMaskFormat() == format); 162 163 if (atlas && atlas->addSubImage(width, height, image, loc)) { 164 return atlas; 165 } 166 167 // If the above fails, then either we have no starting atlas, or the current 168 // one is full. Either way we need to allocate a new atlas 169 170 GrIPoint16 plot; 171 if (!fPlotMgr->newPlot(&plot)) { 172 return NULL; 173 } 174 175 GrAssert(0 == kA8_GrMaskFormat); 176 GrAssert(1 == kA565_GrMaskFormat); 177 if (NULL == fTexture[format]) { 178 GrTextureDesc desc = { 179 kDynamicUpdate_GrTextureFlagBit, 180 kNone_GrAALevel, 181 GR_ATLAS_TEXTURE_WIDTH, 182 GR_ATLAS_TEXTURE_HEIGHT, 183 maskformat2pixelconfig(format) 184 }; 185 fTexture[format] = fGpu->createTexture(desc, NULL, 0); 186 if (NULL == fTexture[format]) { 187 return NULL; 188 } 189 } 190 191 GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format); 192 if (!newAtlas->addSubImage(width, height, image, loc)) { 193 delete newAtlas; 194 return NULL; 195 } 196 197 newAtlas->fNext = atlas; 198 return newAtlas; 199 } 200 201 void GrAtlasMgr::freePlot(int x, int y) { 202 GrAssert(fPlotMgr->isBusy(x, y)); 203 fPlotMgr->freePlot(x, y); 204 } 205 206 207