blob: 5c951536b62a6f93b690735c98af412454820548 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
reed@google.comac10a2d2010-12-22 21:39:39 +000011#include "GrAtlas.h"
bsalomon@google.com6f379512011-11-16 20:36:03 +000012#include "GrContext.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000013#include "GrGpu.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000014#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
reed@google.com98539c62011-03-15 15:40:16 +000047GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) {
reed@google.comac10a2d2010-12-22 21:39:39 +000048 fAtlasMgr = mgr; // just a pointer, not an owner
49 fNext = NULL;
reed@google.com759c16e2011-03-15 19:15:15 +000050 fTexture = mgr->getTexture(format); // we're not an owner, just a pointer
reed@google.comac10a2d2010-12-22 21:39:39 +000051 fPlot.set(plotX, plotY);
52
53 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
54 GR_ATLAS_HEIGHT - BORDER);
55
reed@google.com98539c62011-03-15 15:40:16 +000056 fMaskFormat = format;
57
reed@google.comac10a2d2010-12-22 21:39:39 +000058#if GR_DEBUG
reed@google.com3ef80cf2011-07-05 19:09:47 +000059// GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
reed@google.comac10a2d2010-12-22 21:39:39 +000060 gCounter += 1;
61#endif
62}
63
64GrAtlas::~GrAtlas() {
65 fAtlasMgr->freePlot(fPlot.fX, fPlot.fY);
66
67 delete fRects;
68
69#if GR_DEBUG
70 --gCounter;
reed@google.com3ef80cf2011-07-05 19:09:47 +000071// GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter);
reed@google.comac10a2d2010-12-22 21:39:39 +000072#endif
73}
74
75static 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
reed@google.com98539c62011-03-15 15:40:16 +000080static uint8_t* zerofill(uint8_t* ptr, int count) {
81 while (--count >= 0) {
82 *ptr++ = 0;
83 }
84 return ptr;
85}
86
reed@google.comac10a2d2010-12-22 21:39:39 +000087bool 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
bsalomon@google.com3582bf92011-06-30 21:32:31 +000093 SkAutoSMalloc<1024> storage;
reed@google.com98539c62011-03-15 15:40:16 +000094 int dstW = width + 2*BORDER;
95 int dstH = height + 2*BORDER;
reed@google.comac10a2d2010-12-22 21:39:39 +000096 if (BORDER) {
reed@google.com98539c62011-03-15 15:40:16 +000097 const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat);
98 const size_t dstRB = dstW * bpp;
bsalomon@google.com7d4679a2011-09-02 22:06:24 +000099 uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB);
reed@google.com98539c62011-03-15 15:40:16 +0000100 Gr_bzero(dst, dstRB); // zero top row
101 dst += dstRB;
reed@google.comac10a2d2010-12-22 21:39:39 +0000102 for (int y = 0; y < height; y++) {
reed@google.com98539c62011-03-15 15:40:16 +0000103 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);
reed@google.comac10a2d2010-12-22 21:39:39 +0000108 }
reed@google.com98539c62011-03-15 15:40:16 +0000109 Gr_bzero(dst, dstRB); // zero bottom row
reed@google.comac10a2d2010-12-22 21:39:39 +0000110 image = storage.get();
111 }
112 adjustForPlot(loc, fPlot);
bsalomon@google.com6f379512011-11-16 20:36:03 +0000113 GrContext* context = fTexture->getContext();
114 // We call the internal version so that we don't force a flush. We assume
115 // our caller is smart and hasn't referenced the part of the texture we're
116 // about to update since the last flush.
117 context->internalWriteTexturePixels(fTexture, loc->fX, loc->fY,
118 dstW, dstH, fTexture->config(),
119 image, 0,
120 GrContext::kDontFlush_PixelOpsFlag);
reed@google.comac10a2d2010-12-22 21:39:39 +0000121
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
130GrAtlasMgr::GrAtlasMgr(GrGpu* gpu) {
131 fGpu = gpu;
132 gpu->ref();
reed@google.com759c16e2011-03-15 19:15:15 +0000133 Gr_bzero(fTexture, sizeof(fTexture));
reed@google.comac10a2d2010-12-22 21:39:39 +0000134 fPlotMgr = new GrPlotMgr(GR_PLOT_WIDTH, GR_PLOT_HEIGHT);
135}
136
137GrAtlasMgr::~GrAtlasMgr() {
reed@google.com759c16e2011-03-15 19:15:15 +0000138 for (size_t i = 0; i < GR_ARRAY_COUNT(fTexture); i++) {
139 GrSafeUnref(fTexture[i]);
140 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000141 delete fPlotMgr;
142 fGpu->unref();
143}
144
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000145static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) {
reed@google.com98539c62011-03-15 15:40:16 +0000146 switch (format) {
147 case kA8_GrMaskFormat:
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000148 return kAlpha_8_GrPixelConfig;
reed@google.com98539c62011-03-15 15:40:16 +0000149 case kA565_GrMaskFormat:
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000150 return kRGB_565_GrPixelConfig;
caryclark@google.com1eeaf0b2011-06-22 13:19:43 +0000151 case kA888_GrMaskFormat:
bsalomon@google.comc4364992011-11-07 15:54:49 +0000152 return kSkia8888_PM_GrPixelConfig;
reed@google.com98539c62011-03-15 15:40:16 +0000153 default:
154 GrAssert(!"unknown maskformat");
155 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000156 return kUnknown_GrPixelConfig;
reed@google.com98539c62011-03-15 15:40:16 +0000157}
158
reed@google.comac10a2d2010-12-22 21:39:39 +0000159GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
160 int width, int height, const void* image,
reed@google.com98539c62011-03-15 15:40:16 +0000161 GrMaskFormat format,
reed@google.comac10a2d2010-12-22 21:39:39 +0000162 GrIPoint16* loc) {
reed@google.com98539c62011-03-15 15:40:16 +0000163 GrAssert(NULL == atlas || atlas->getMaskFormat() == format);
reed@google.com759c16e2011-03-15 19:15:15 +0000164
reed@google.comac10a2d2010-12-22 21:39:39 +0000165 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
reed@google.com759c16e2011-03-15 19:15:15 +0000177 GrAssert(0 == kA8_GrMaskFormat);
178 GrAssert(1 == kA565_GrMaskFormat);
179 if (NULL == fTexture[format]) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000180 GrTextureDesc desc = {
181 kDynamicUpdate_GrTextureFlagBit,
182 kNone_GrAALevel,
reed@google.com98539c62011-03-15 15:40:16 +0000183 GR_ATLAS_TEXTURE_WIDTH,
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 GR_ATLAS_TEXTURE_HEIGHT,
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +0000185 { maskformat2pixelconfig(format) }
reed@google.comac10a2d2010-12-22 21:39:39 +0000186 };
reed@google.com759c16e2011-03-15 19:15:15 +0000187 fTexture[format] = fGpu->createTexture(desc, NULL, 0);
188 if (NULL == fTexture[format]) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000189 return NULL;
190 }
191 }
192
reed@google.com98539c62011-03-15 15:40:16 +0000193 GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format);
reed@google.comac10a2d2010-12-22 21:39:39 +0000194 if (!newAtlas->addSubImage(width, height, image, loc)) {
195 delete newAtlas;
196 return NULL;
197 }
198
199 newAtlas->fNext = atlas;
200 return newAtlas;
201}
202
203void GrAtlasMgr::freePlot(int x, int y) {
204 GrAssert(fPlotMgr->isBusy(x, y));
205 fPlotMgr->freePlot(x, y);
206}
207
reed@google.comac10a2d2010-12-22 21:39:39 +0000208