Home | History | Annotate | Download | only in gpu
      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