aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrAtlas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpu/GrAtlas.cpp')
-rw-r--r--src/gpu/GrAtlas.cpp200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/gpu/GrAtlas.cpp b/src/gpu/GrAtlas.cpp
new file mode 100644
index 0000000000..0838895a13
--- /dev/null
+++ b/src/gpu/GrAtlas.cpp
@@ -0,0 +1,200 @@
+
+/*
+ * 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 "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);
+ fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image, 0);
+
+ // 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 kRGBA_8888_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);
+}
+
+