blob: ea32719d192ae891e4eaf025f36674726b958e9d [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrAtlas.h"
19#include "GrGpu.h"
20#include "GrMemory.h"
21#include "GrRectanizer.h"
22#include "GrPlotMgr.h"
23
24#if 0
25#define GR_PLOT_WIDTH 8
26#define GR_PLOT_HEIGHT 4
27#define GR_ATLAS_WIDTH 256
28#define GR_ATLAS_HEIGHT 256
29
30#define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH)
31#define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT)
32
33#else
34
35#define GR_ATLAS_TEXTURE_WIDTH 1024
36#define GR_ATLAS_TEXTURE_HEIGHT 2048
37
38#define GR_ATLAS_WIDTH 341
39#define GR_ATLAS_HEIGHT 341
40
41#define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH)
42#define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT)
43
44#endif
45
46///////////////////////////////////////////////////////////////////////////////
47
48#define BORDER 1
49
50#if GR_DEBUG
51 static int gCounter;
52#endif
53
reed@google.com98539c62011-03-15 15:40:16 +000054GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) {
reed@google.comac10a2d2010-12-22 21:39:39 +000055 fAtlasMgr = mgr; // just a pointer, not an owner
56 fNext = NULL;
57 fTexture = mgr->getTexture(); // we're not an owner, just a pointer
58 fPlot.set(plotX, plotY);
59
60 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
61 GR_ATLAS_HEIGHT - BORDER);
62
reed@google.com98539c62011-03-15 15:40:16 +000063 fMaskFormat = format;
64
reed@google.comac10a2d2010-12-22 21:39:39 +000065#if GR_DEBUG
66 GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
67 gCounter += 1;
68#endif
69}
70
71GrAtlas::~GrAtlas() {
72 fAtlasMgr->freePlot(fPlot.fX, fPlot.fY);
73
74 delete fRects;
75
76#if GR_DEBUG
77 --gCounter;
78 GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter);
79#endif
80}
81
82static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) {
83 loc->fX += plot.fX * GR_ATLAS_WIDTH;
84 loc->fY += plot.fY * GR_ATLAS_HEIGHT;
85}
86
reed@google.com98539c62011-03-15 15:40:16 +000087static uint8_t* zerofill(uint8_t* ptr, int count) {
88 while (--count >= 0) {
89 *ptr++ = 0;
90 }
91 return ptr;
92}
93
reed@google.comac10a2d2010-12-22 21:39:39 +000094bool GrAtlas::addSubImage(int width, int height, const void* image,
95 GrIPoint16* loc) {
96 if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
97 return false;
98 }
99
100 GrAutoSMalloc<1024> storage;
reed@google.com98539c62011-03-15 15:40:16 +0000101 int dstW = width + 2*BORDER;
102 int dstH = height + 2*BORDER;
reed@google.comac10a2d2010-12-22 21:39:39 +0000103 if (BORDER) {
reed@google.com98539c62011-03-15 15:40:16 +0000104 const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat);
105 const size_t dstRB = dstW * bpp;
106 uint8_t* dst = (uint8_t*)storage.realloc(dstH * dstRB);
107 Gr_bzero(dst, dstRB); // zero top row
108 dst += dstRB;
reed@google.comac10a2d2010-12-22 21:39:39 +0000109 for (int y = 0; y < height; y++) {
reed@google.com98539c62011-03-15 15:40:16 +0000110 dst = zerofill(dst, bpp); // zero left edge
111 memcpy(dst, image, width * bpp);
112 dst += width * bpp;
113 dst = zerofill(dst, bpp); // zero right edge
114 image = (const void*)((const char*)image + width * bpp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000115 }
reed@google.com98539c62011-03-15 15:40:16 +0000116 Gr_bzero(dst, dstRB); // zero bottom row
reed@google.comac10a2d2010-12-22 21:39:39 +0000117 image = storage.get();
118 }
119 adjustForPlot(loc, fPlot);
reed@google.com98539c62011-03-15 15:40:16 +0000120 fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image);
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();
133 fTexture = NULL;
134 fPlotMgr = new GrPlotMgr(GR_PLOT_WIDTH, GR_PLOT_HEIGHT);
135}
136
137GrAtlasMgr::~GrAtlasMgr() {
138 GrSafeUnref(fTexture);
139 delete fPlotMgr;
140 fGpu->unref();
141}
142
reed@google.com98539c62011-03-15 15:40:16 +0000143static GrTexture::PixelConfig maskformat2pixelconfig(GrMaskFormat format) {
144 switch (format) {
145 case kA8_GrMaskFormat:
146 return GrTexture::kAlpha_8_PixelConfig;
147 case kA565_GrMaskFormat:
148 return GrTexture::kRGB_565_PixelConfig;
149 default:
150 GrAssert(!"unknown maskformat");
151 }
152 return GrTexture::kUnknown_PixelConfig;
153}
154
reed@google.comac10a2d2010-12-22 21:39:39 +0000155GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
156 int width, int height, const void* image,
reed@google.com98539c62011-03-15 15:40:16 +0000157 GrMaskFormat format,
reed@google.comac10a2d2010-12-22 21:39:39 +0000158 GrIPoint16* loc) {
reed@google.com98539c62011-03-15 15:40:16 +0000159 GrAssert(NULL == atlas || atlas->getMaskFormat() == format);
reed@google.comac10a2d2010-12-22 21:39:39 +0000160 if (atlas && atlas->addSubImage(width, height, image, loc)) {
161 return atlas;
162 }
163
164 // If the above fails, then either we have no starting atlas, or the current
165 // one is full. Either way we need to allocate a new atlas
166
167 GrIPoint16 plot;
168 if (!fPlotMgr->newPlot(&plot)) {
169 return NULL;
170 }
171
172 if (NULL == fTexture) {
173 GrGpu::TextureDesc desc = {
reed@google.com98539c62011-03-15 15:40:16 +0000174 GrGpu::kDynamicUpdate_TextureFlag,
reed@google.comac10a2d2010-12-22 21:39:39 +0000175 GrGpu::kNone_AALevel,
reed@google.com98539c62011-03-15 15:40:16 +0000176 GR_ATLAS_TEXTURE_WIDTH,
reed@google.comac10a2d2010-12-22 21:39:39 +0000177 GR_ATLAS_TEXTURE_HEIGHT,
reed@google.com98539c62011-03-15 15:40:16 +0000178 maskformat2pixelconfig(format)
reed@google.comac10a2d2010-12-22 21:39:39 +0000179 };
180 fTexture = fGpu->createTexture(desc, NULL, 0);
181 if (NULL == fTexture) {
182 return NULL;
183 }
184 }
185
reed@google.com98539c62011-03-15 15:40:16 +0000186 GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format);
reed@google.comac10a2d2010-12-22 21:39:39 +0000187 if (!newAtlas->addSubImage(width, height, image, loc)) {
188 delete newAtlas;
189 return NULL;
190 }
191
192 newAtlas->fNext = atlas;
193 return newAtlas;
194}
195
196void GrAtlasMgr::freePlot(int x, int y) {
197 GrAssert(fPlotMgr->isBusy(x, y));
198 fPlotMgr->freePlot(x, y);
199}
200
201void GrAtlasMgr::abandonAll() {
202#if 0
203 GrAtlas** curr = fList.begin();
204 GrAtlas** stop = fList.end();
205 for (; curr < stop; curr++) {
206 (*curr)->texture()->abandon();
207 delete *curr;
208 }
209 fList.reset();
210#endif
211}
212
213