blob: b55a02908c267d58ee26a265b5ed1abbd1fc219c [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
54GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY) {
55 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
63#if GR_DEBUG
64 GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
65 gCounter += 1;
66#endif
67}
68
69GrAtlas::~GrAtlas() {
70 fAtlasMgr->freePlot(fPlot.fX, fPlot.fY);
71
72 delete fRects;
73
74#if GR_DEBUG
75 --gCounter;
76 GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter);
77#endif
78}
79
80static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) {
81 loc->fX += plot.fX * GR_ATLAS_WIDTH;
82 loc->fY += plot.fY * GR_ATLAS_HEIGHT;
83}
84
85bool GrAtlas::addSubImage(int width, int height, const void* image,
86 GrIPoint16* loc) {
87 if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
88 return false;
89 }
90
91 GrAutoSMalloc<1024> storage;
92 int srcW = width + 2*BORDER;
93 int srcH = height + 2*BORDER;
94 if (BORDER) {
95 uint8_t* ptr = (uint8_t*)storage.realloc(srcW * srcH);
96 Gr_bzero(ptr, srcW); // zero top row
97 ptr += srcW;
98 for (int y = 0; y < height; y++) {
99 *ptr++ = 0; // zero left edge
100 memcpy(ptr, image, width); ptr += width;
101 *ptr++ = 0; // zero right edge
102 image = (const void*)((const char*)image + width);
103 }
104 Gr_bzero(ptr, srcW); // zero bottom row
105 image = storage.get();
106 }
107 adjustForPlot(loc, fPlot);
108 fTexture->uploadTextureData(loc->fX, loc->fY, srcW, srcH, image);
109
110 // now tell the caller to skip the top/left BORDER
111 loc->fX += BORDER;
112 loc->fY += BORDER;
113 return true;
114}
115
116///////////////////////////////////////////////////////////////////////////////
117
118GrAtlasMgr::GrAtlasMgr(GrGpu* gpu) {
119 fGpu = gpu;
120 gpu->ref();
121 fTexture = NULL;
122 fPlotMgr = new GrPlotMgr(GR_PLOT_WIDTH, GR_PLOT_HEIGHT);
123}
124
125GrAtlasMgr::~GrAtlasMgr() {
126 GrSafeUnref(fTexture);
127 delete fPlotMgr;
128 fGpu->unref();
129}
130
131GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
132 int width, int height, const void* image,
133 GrIPoint16* loc) {
134 if (atlas && atlas->addSubImage(width, height, image, loc)) {
135 return atlas;
136 }
137
138 // If the above fails, then either we have no starting atlas, or the current
139 // one is full. Either way we need to allocate a new atlas
140
141 GrIPoint16 plot;
142 if (!fPlotMgr->newPlot(&plot)) {
143 return NULL;
144 }
145
146 if (NULL == fTexture) {
147 GrGpu::TextureDesc desc = {
148 GrGpu::kDynamicUpdate_TextureFlag,
149 GrGpu::kNone_AALevel,
150 GR_ATLAS_TEXTURE_WIDTH,
151 GR_ATLAS_TEXTURE_HEIGHT,
152 GrTexture::kAlpha_8_PixelConfig
153 };
154 fTexture = fGpu->createTexture(desc, NULL, 0);
155 if (NULL == fTexture) {
156 return NULL;
157 }
158 }
159
160 GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY);
161 if (!newAtlas->addSubImage(width, height, image, loc)) {
162 delete newAtlas;
163 return NULL;
164 }
165
166 newAtlas->fNext = atlas;
167 return newAtlas;
168}
169
170void GrAtlasMgr::freePlot(int x, int y) {
171 GrAssert(fPlotMgr->isBusy(x, y));
172 fPlotMgr->freePlot(x, y);
173}
174
175void GrAtlasMgr::abandonAll() {
176#if 0
177 GrAtlas** curr = fList.begin();
178 GrAtlas** stop = fList.end();
179 for (; curr < stop; curr++) {
180 (*curr)->texture()->abandon();
181 delete *curr;
182 }
183 fList.reset();
184#endif
185}
186
187