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 GrAtlas::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 
     64 GrAtlas::~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 
     75 static 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 
     80 static uint8_t* zerofill(uint8_t* ptr, int count) {
     81     while (--count >= 0) {
     82         *ptr++ = 0;
     83     }
     84     return ptr;
     85 }
     86 
     87 bool 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 pass the flag that does not force a flush. We assume our caller is
    115     // smart and hasn't referenced the part of the texture we're about to update
    116     // since the last flush.
    117     context->writeTexturePixels(fTexture,
    118                                 loc->fX, loc->fY, dstW, dstH,
    119                                 fTexture->config(), 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 
    130 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu) {
    131     fGpu = gpu;
    132     gpu->ref();
    133     Gr_bzero(fTexture, sizeof(fTexture));
    134     fPlotMgr = SkNEW_ARGS(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         case kA888_GrMaskFormat:
    152             return kSkia8888_PM_GrPixelConfig;
    153         default:
    154             GrAssert(!"unknown maskformat");
    155     }
    156     return kUnknown_GrPixelConfig;
    157 }
    158 
    159 GrAtlas* 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         // TODO: Update this to use the cache rather than directly creating a texture.
    181         GrTextureDesc desc;
    182         desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
    183         desc.fWidth = GR_ATLAS_TEXTURE_WIDTH;
    184         desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT;
    185         desc.fConfig = maskformat2pixelconfig(format);
    186 
    187         fTexture[format] = fGpu->createTexture(desc, NULL, 0);
    188         if (NULL == fTexture[format]) {
    189             return NULL;
    190         }
    191     }
    192 
    193     GrAtlas* newAtlas = SkNEW_ARGS(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 
    203 void GrAtlasMgr::freePlot(int x, int y) {
    204     GrAssert(fPlotMgr->isBusy(x, y));
    205     fPlotMgr->freePlot(x, y);
    206 }
    207