diff options
Diffstat (limited to 'src/gpu/GrAtlas.cpp')
-rw-r--r-- | src/gpu/GrAtlas.cpp | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/src/gpu/GrAtlas.cpp b/src/gpu/GrAtlas.cpp new file mode 100644 index 0000000..17464ba --- /dev/null +++ b/src/gpu/GrAtlas.cpp @@ -0,0 +1,208 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#include "GrAtlas.h" +#include "GrContext.h" +#include "GrGpu.h" +#include "GrRectanizer.h" +#include "GrPlotMgr.h" + +#if 0 +#define GR_PLOT_WIDTH 8 +#define GR_PLOT_HEIGHT 4 +#define GR_ATLAS_WIDTH 256 +#define GR_ATLAS_HEIGHT 256 + +#define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH) +#define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT) + +#else + +#define GR_ATLAS_TEXTURE_WIDTH 1024 +#define GR_ATLAS_TEXTURE_HEIGHT 2048 + +#define GR_ATLAS_WIDTH 341 +#define GR_ATLAS_HEIGHT 341 + +#define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH) +#define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT) + +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#define BORDER 1 + +#if GR_DEBUG + static int gCounter; +#endif + +GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) { + fAtlasMgr = mgr; // just a pointer, not an owner + fNext = NULL; + fTexture = mgr->getTexture(format); // we're not an owner, just a pointer + fPlot.set(plotX, plotY); + + fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER, + GR_ATLAS_HEIGHT - BORDER); + + fMaskFormat = format; + +#if GR_DEBUG +// GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter); + gCounter += 1; +#endif +} + +GrAtlas::~GrAtlas() { + fAtlasMgr->freePlot(fPlot.fX, fPlot.fY); + + delete fRects; + +#if GR_DEBUG + --gCounter; +// GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter); +#endif +} + +static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) { + loc->fX += plot.fX * GR_ATLAS_WIDTH; + loc->fY += plot.fY * GR_ATLAS_HEIGHT; +} + +static uint8_t* zerofill(uint8_t* ptr, int count) { + while (--count >= 0) { + *ptr++ = 0; + } + return ptr; +} + +bool GrAtlas::addSubImage(int width, int height, const void* image, + GrIPoint16* loc) { + if (!fRects->addRect(width + BORDER, height + BORDER, loc)) { + return false; + } + + SkAutoSMalloc<1024> storage; + int dstW = width + 2*BORDER; + int dstH = height + 2*BORDER; + if (BORDER) { + const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat); + const size_t dstRB = dstW * bpp; + uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB); + Gr_bzero(dst, dstRB); // zero top row + dst += dstRB; + for (int y = 0; y < height; y++) { + dst = zerofill(dst, bpp); // zero left edge + memcpy(dst, image, width * bpp); + dst += width * bpp; + dst = zerofill(dst, bpp); // zero right edge + image = (const void*)((const char*)image + width * bpp); + } + Gr_bzero(dst, dstRB); // zero bottom row + image = storage.get(); + } + adjustForPlot(loc, fPlot); + GrContext* context = fTexture->getContext(); + // We call the internal version so that we don't force a flush. We assume + // our caller is smart and hasn't referenced the part of the texture we're + // about to update since the last flush. + context->internalWriteTexturePixels(fTexture, loc->fX, loc->fY, + dstW, dstH, fTexture->config(), + image, 0, + GrContext::kDontFlush_PixelOpsFlag); + + // now tell the caller to skip the top/left BORDER + loc->fX += BORDER; + loc->fY += BORDER; + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +GrAtlasMgr::GrAtlasMgr(GrGpu* gpu) { + fGpu = gpu; + gpu->ref(); + Gr_bzero(fTexture, sizeof(fTexture)); + fPlotMgr = new GrPlotMgr(GR_PLOT_WIDTH, GR_PLOT_HEIGHT); +} + +GrAtlasMgr::~GrAtlasMgr() { + for (size_t i = 0; i < GR_ARRAY_COUNT(fTexture); i++) { + GrSafeUnref(fTexture[i]); + } + delete fPlotMgr; + fGpu->unref(); +} + +static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) { + switch (format) { + case kA8_GrMaskFormat: + return kAlpha_8_GrPixelConfig; + case kA565_GrMaskFormat: + return kRGB_565_GrPixelConfig; + case kA888_GrMaskFormat: + return kSkia8888_PM_GrPixelConfig; + default: + GrAssert(!"unknown maskformat"); + } + return kUnknown_GrPixelConfig; +} + +GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas, + int width, int height, const void* image, + GrMaskFormat format, + GrIPoint16* loc) { + GrAssert(NULL == atlas || atlas->getMaskFormat() == format); + + if (atlas && atlas->addSubImage(width, height, image, loc)) { + return atlas; + } + + // If the above fails, then either we have no starting atlas, or the current + // one is full. Either way we need to allocate a new atlas + + GrIPoint16 plot; + if (!fPlotMgr->newPlot(&plot)) { + return NULL; + } + + GrAssert(0 == kA8_GrMaskFormat); + GrAssert(1 == kA565_GrMaskFormat); + if (NULL == fTexture[format]) { + GrTextureDesc desc = { + kDynamicUpdate_GrTextureFlagBit, + kNone_GrAALevel, + GR_ATLAS_TEXTURE_WIDTH, + GR_ATLAS_TEXTURE_HEIGHT, + maskformat2pixelconfig(format) + }; + fTexture[format] = fGpu->createTexture(desc, NULL, 0); + if (NULL == fTexture[format]) { + return NULL; + } + } + + GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format); + if (!newAtlas->addSubImage(width, height, image, loc)) { + delete newAtlas; + return NULL; + } + + newAtlas->fNext = atlas; + return newAtlas; +} + +void GrAtlasMgr::freePlot(int x, int y) { + GrAssert(fPlotMgr->isBusy(x, y)); + fPlotMgr->freePlot(x, y); +} + + |