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 47GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) { 48 fAtlasMgr = mgr; // just a pointer, not an owner 49 fNext = NULL; 50 fTexture = mgr->getTexture(format); // we're not an owner, just a pointer 51 fPlot.set(plotX, plotY); 52 53 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER, 54 GR_ATLAS_HEIGHT - BORDER); 55 56 fMaskFormat = format; 57 58#if GR_DEBUG 59// GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter); 60 gCounter += 1; 61#endif 62} 63 64GrAtlas::~GrAtlas() { 65 fAtlasMgr->freePlot(fPlot.fX, fPlot.fY); 66 67 delete fRects; 68 69#if GR_DEBUG 70 --gCounter; 71// GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter); 72#endif 73} 74 75static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) { 76 loc->fX += plot.fX * GR_ATLAS_WIDTH; 77 loc->fY += plot.fY * GR_ATLAS_HEIGHT; 78} 79 80static uint8_t* zerofill(uint8_t* ptr, int count) { 81 while (--count >= 0) { 82 *ptr++ = 0; 83 } 84 return ptr; 85} 86 87bool GrAtlas::addSubImage(int width, int height, const void* image, 88 GrIPoint16* loc) { 89 if (!fRects->addRect(width + BORDER, height + BORDER, loc)) { 90 return false; 91 } 92 93 SkAutoSMalloc<1024> storage; 94 int dstW = width + 2*BORDER; 95 int dstH = height + 2*BORDER; 96 if (BORDER) { 97 const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat); 98 const size_t dstRB = dstW * bpp; 99 uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB); 100 Gr_bzero(dst, dstRB); // zero top row 101 dst += dstRB; 102 for (int y = 0; y < height; y++) { 103 dst = zerofill(dst, bpp); // zero left edge 104 memcpy(dst, image, width * bpp); 105 dst += width * bpp; 106 dst = zerofill(dst, bpp); // zero right edge 107 image = (const void*)((const char*)image + width * bpp); 108 } 109 Gr_bzero(dst, dstRB); // zero bottom row 110 image = storage.get(); 111 } 112 adjustForPlot(loc, fPlot); 113 GrContext* context = fTexture->getContext(); 114 // We call the internal version so that we don't force a flush. We assume 115 // our caller is smart and hasn't referenced the part of the texture we're 116 // about to update since the last flush. 117 context->internalWriteTexturePixels(fTexture, loc->fX, loc->fY, 118 dstW, dstH, fTexture->config(), 119 image, 0, 120 GrContext::kDontFlush_PixelOpsFlag); 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 130GrAtlasMgr::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 137GrAtlasMgr::~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 145static 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 case kA888_GrMaskFormat: 152 return kSkia8888_PM_GrPixelConfig; 153 default: 154 GrAssert(!"unknown maskformat"); 155 } 156 return kUnknown_GrPixelConfig; 157} 158 159GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas, 160 int width, int height, const void* image, 161 GrMaskFormat format, 162 GrIPoint16* loc) { 163 GrAssert(NULL == atlas || atlas->getMaskFormat() == format); 164 165 if (atlas && atlas->addSubImage(width, height, image, loc)) { 166 return atlas; 167 } 168 169 // If the above fails, then either we have no starting atlas, or the current 170 // one is full. Either way we need to allocate a new atlas 171 172 GrIPoint16 plot; 173 if (!fPlotMgr->newPlot(&plot)) { 174 return NULL; 175 } 176 177 GrAssert(0 == kA8_GrMaskFormat); 178 GrAssert(1 == kA565_GrMaskFormat); 179 if (NULL == fTexture[format]) { 180 GrTextureDesc desc = { 181 kDynamicUpdate_GrTextureFlagBit, 182 GR_ATLAS_TEXTURE_WIDTH, 183 GR_ATLAS_TEXTURE_HEIGHT, 184 maskformat2pixelconfig(format), 185 {0} // samples 186 }; 187 fTexture[format] = fGpu->createTexture(desc, NULL, 0); 188 if (NULL == fTexture[format]) { 189 return NULL; 190 } 191 } 192 193 GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format); 194 if (!newAtlas->addSubImage(width, height, image, loc)) { 195 delete newAtlas; 196 return NULL; 197 } 198 199 newAtlas->fNext = atlas; 200 return newAtlas; 201} 202 203void GrAtlasMgr::freePlot(int x, int y) { 204 GrAssert(fPlotMgr->isBusy(x, y)); 205 fPlotMgr->freePlot(x, y); 206} 207 208 209