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 #include "GrAtlas.h"
     10 #include "GrContext.h"
     11 #include "GrGpu.h"
     12 #include "GrRectanizer.h"
     13 
     14 #if 0
     15 #define GR_PLOT_WIDTH   8
     16 #define GR_PLOT_HEIGHT  4
     17 #define GR_ATLAS_WIDTH  256
     18 #define GR_ATLAS_HEIGHT 256
     19 
     20 #define GR_ATLAS_TEXTURE_WIDTH  (GR_PLOT_WIDTH * GR_ATLAS_WIDTH)
     21 #define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT)
     22 
     23 #else
     24 
     25 #define GR_ATLAS_TEXTURE_WIDTH  1024
     26 #define GR_ATLAS_TEXTURE_HEIGHT 2048
     27 
     28 #define GR_ATLAS_WIDTH  256
     29 #define GR_ATLAS_HEIGHT 256
     30 
     31 #define GR_PLOT_WIDTH   (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH)
     32 #define GR_PLOT_HEIGHT  (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT)
     33 
     34 #endif
     35 
     36 ///////////////////////////////////////////////////////////////////////////////
     37 
     38 #define BORDER      1
     39 
     40 #ifdef SK_DEBUG
     41     static int gCounter;
     42 #endif
     43 
     44 // for testing
     45 #define FONT_CACHE_STATS 0
     46 #if FONT_CACHE_STATS
     47 static int g_UploadCount = 0;
     48 #endif
     49 
     50 GrPlot::GrPlot() : fDrawToken(NULL, 0)
     51                  , fNext(NULL)
     52                  , fTexture(NULL)
     53                  , fAtlasMgr(NULL)
     54                  , fBytesPerPixel(1)
     55 {
     56     fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
     57                                    GR_ATLAS_HEIGHT - BORDER);
     58     fOffset.set(0, 0);
     59 }
     60 
     61 GrPlot::~GrPlot() {
     62     delete fRects;
     63 }
     64 
     65 static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) {
     66     loc->fX += offset.fX * GR_ATLAS_WIDTH;
     67     loc->fY += offset.fY * GR_ATLAS_HEIGHT;
     68 }
     69 
     70 static inline uint8_t* zero_fill(uint8_t* ptr, size_t count) {
     71     sk_bzero(ptr, count);
     72     return ptr + count;
     73 }
     74 
     75 bool GrPlot::addSubImage(int width, int height, const void* image,
     76                           GrIPoint16* loc) {
     77     if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
     78         return false;
     79     }
     80 
     81     SkAutoSMalloc<1024> storage;
     82     int dstW = width + 2*BORDER;
     83     int dstH = height + 2*BORDER;
     84     if (BORDER) {
     85         const size_t dstRB = dstW * fBytesPerPixel;
     86         uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB);
     87         sk_bzero(dst, dstRB);                // zero top row
     88         dst += dstRB;
     89         for (int y = 0; y < height; y++) {
     90             dst = zero_fill(dst, fBytesPerPixel);   // zero left edge
     91             memcpy(dst, image, width * fBytesPerPixel);
     92             dst += width * fBytesPerPixel;
     93             dst = zero_fill(dst, fBytesPerPixel);   // zero right edge
     94             image = (const void*)((const char*)image + width * fBytesPerPixel);
     95         }
     96         sk_bzero(dst, dstRB);                // zero bottom row
     97         image = storage.get();
     98     }
     99     adjust_for_offset(loc, fOffset);
    100     GrContext* context = fTexture->getContext();
    101     // We pass the flag that does not force a flush. We assume our caller is
    102     // smart and hasn't referenced the part of the texture we're about to update
    103     // since the last flush.
    104     context->writeTexturePixels(fTexture,
    105                                 loc->fX, loc->fY, dstW, dstH,
    106                                 fTexture->config(), image, 0,
    107                                 GrContext::kDontFlush_PixelOpsFlag);
    108 
    109     // now tell the caller to skip the top/left BORDER
    110     loc->fX += BORDER;
    111     loc->fY += BORDER;
    112 
    113 #if FONT_CACHE_STATS
    114     ++g_UploadCount;
    115 #endif
    116 
    117     return true;
    118 }
    119 
    120 ///////////////////////////////////////////////////////////////////////////////
    121 
    122 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) {
    123     fGpu = gpu;
    124     fPixelConfig = config;
    125     gpu->ref();
    126     fTexture = NULL;
    127 
    128     // set up allocated plots
    129     size_t bpp = GrBytesPerPixel(fPixelConfig);
    130     fPlots = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT));
    131     fFreePlots = NULL;
    132     GrPlot* currPlot = fPlots;
    133     for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) {
    134         for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) {
    135             currPlot->fAtlasMgr = this;
    136             currPlot->fOffset.set(x, y);
    137             currPlot->fBytesPerPixel = bpp;
    138 
    139             // add to free list
    140             currPlot->fNext = fFreePlots;
    141             fFreePlots = currPlot;
    142 
    143             ++currPlot;
    144         }
    145     }
    146 }
    147 
    148 GrAtlasMgr::~GrAtlasMgr() {
    149     SkSafeUnref(fTexture);
    150     SkDELETE_ARRAY(fPlots);
    151 
    152     fGpu->unref();
    153 #if FONT_CACHE_STATS
    154       GrPrintf("Num uploads: %d\n", g_UploadCount);
    155 #endif
    156 }
    157 
    158 GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
    159                                int width, int height, const void* image,
    160                                GrIPoint16* loc) {
    161     // iterate through entire plot list, see if we can find a hole
    162     GrPlot* plotIter = atlas->fPlots;
    163     while (plotIter) {
    164         if (plotIter->addSubImage(width, height, image, loc)) {
    165             return plotIter;
    166         }
    167         plotIter = plotIter->fNext;
    168     }
    169 
    170     // If the above fails, then either we have no starting plot, or the current
    171     // plot list is full. Either way we need to allocate a new plot
    172     GrPlot* newPlot = this->allocPlot();
    173     if (NULL == newPlot) {
    174         return NULL;
    175     }
    176 
    177     if (NULL == fTexture) {
    178         // TODO: Update this to use the cache rather than directly creating a texture.
    179         GrTextureDesc desc;
    180         desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
    181         desc.fWidth = GR_ATLAS_TEXTURE_WIDTH;
    182         desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT;
    183         desc.fConfig = fPixelConfig;
    184 
    185         fTexture = fGpu->createTexture(desc, NULL, 0);
    186         if (NULL == fTexture) {
    187             return NULL;
    188         }
    189     }
    190     // be sure to set texture for fast lookup
    191     newPlot->fTexture = fTexture;
    192 
    193     if (!newPlot->addSubImage(width, height, image, loc)) {
    194         this->freePlot(newPlot);
    195         return NULL;
    196     }
    197 
    198     // new plot, put at head
    199     newPlot->fNext = atlas->fPlots;
    200     atlas->fPlots = newPlot;
    201 
    202     return newPlot;
    203 }
    204 
    205 bool GrAtlasMgr::removeUnusedPlots(GrAtlas* atlas) {
    206 
    207     // GrPlot** is used so that the head element can be easily
    208     // modified when the first element is deleted
    209     GrPlot** plotRef = &atlas->fPlots;
    210     GrPlot* plot = atlas->fPlots;
    211     bool removed = false;
    212     while (NULL != plot) {
    213         if (plot->drawToken().isIssued()) {
    214             *plotRef = plot->fNext;
    215             this->freePlot(plot);
    216             plot = *plotRef;
    217             removed = true;
    218         } else {
    219             plotRef = &plot->fNext;
    220             plot = plot->fNext;
    221         }
    222     }
    223 
    224     return removed;
    225 }
    226 
    227 void GrAtlasMgr::deletePlotList(GrPlot* plot) {
    228     while (NULL != plot) {
    229         GrPlot* next = plot->fNext;
    230         this->freePlot(plot);
    231         plot = next;
    232     }
    233 }
    234 
    235 GrPlot* GrAtlasMgr::allocPlot() {
    236     if (NULL == fFreePlots) {
    237         return NULL;
    238     } else {
    239         GrPlot* alloc = fFreePlots;
    240         fFreePlots = alloc->fNext;
    241 #ifdef SK_DEBUG
    242 //        GrPrintf(" GrPlot %p [%d %d] %d\n", this, alloc->fOffset.fX, alloc->fOffset.fY, gCounter);
    243         gCounter += 1;
    244 #endif
    245         return alloc;
    246     }
    247 
    248 }
    249 
    250 void GrAtlasMgr::freePlot(GrPlot* plot) {
    251     SkASSERT(this == plot->fAtlasMgr);
    252 
    253     plot->fRects->reset();
    254     plot->fNext = fFreePlots;
    255     fFreePlots = plot;
    256 
    257 #ifdef SK_DEBUG
    258     --gCounter;
    259 //    GrPrintf("~GrPlot %p [%d %d] %d\n", this, plot->fOffset.fX, plot->fOffset.fY, gCounter);
    260 #endif
    261 }
    262