1 /*
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
GrAtlas(GrAtlasMgr * mgr,int plotX,int plotY,GrMaskFormat format)54 GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) {
55 fAtlasMgr = mgr; // just a pointer, not an owner
56 fNext = NULL;
57 fTexture = mgr->getTexture(format); // 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 fMaskFormat = format;
64
65 #if GR_DEBUG
66 GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
67 gCounter += 1;
68 #endif
69 }
70
~GrAtlas()71 GrAtlas::~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
adjustForPlot(GrIPoint16 * loc,const GrIPoint16 & plot)82 static 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
zerofill(uint8_t * ptr,int count)87 static uint8_t* zerofill(uint8_t* ptr, int count) {
88 while (--count >= 0) {
89 *ptr++ = 0;
90 }
91 return ptr;
92 }
93
addSubImage(int width,int height,const void * image,GrIPoint16 * loc)94 bool 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;
101 int dstW = width + 2*BORDER;
102 int dstH = height + 2*BORDER;
103 if (BORDER) {
104 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;
109 for (int y = 0; y < height; y++) {
110 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);
115 }
116 Gr_bzero(dst, dstRB); // zero bottom row
117 image = storage.get();
118 }
119 adjustForPlot(loc, fPlot);
120 fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image);
121
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
GrAtlasMgr(GrGpu * gpu)130 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu) {
131 fGpu = gpu;
132 gpu->ref();
133 Gr_bzero(fTexture, sizeof(fTexture));
134 fPlotMgr = new GrPlotMgr(GR_PLOT_WIDTH, GR_PLOT_HEIGHT);
135 }
136
~GrAtlasMgr()137 GrAtlasMgr::~GrAtlasMgr() {
138 for (size_t i = 0; i < GR_ARRAY_COUNT(fTexture); i++) {
139 GrSafeUnref(fTexture[i]);
140 }
141 delete fPlotMgr;
142 fGpu->unref();
143 }
144
maskformat2pixelconfig(GrMaskFormat format)145 static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) {
146 switch (format) {
147 case kA8_GrMaskFormat:
148 return kAlpha_8_GrPixelConfig;
149 case kA565_GrMaskFormat:
150 return kRGB_565_GrPixelConfig;
151 default:
152 GrAssert(!"unknown maskformat");
153 }
154 return kUnknown_GrPixelConfig;
155 }
156
addToAtlas(GrAtlas * atlas,int width,int height,const void * image,GrMaskFormat format,GrIPoint16 * loc)157 GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
158 int width, int height, const void* image,
159 GrMaskFormat format,
160 GrIPoint16* loc) {
161 GrAssert(NULL == atlas || atlas->getMaskFormat() == format);
162
163 if (atlas && atlas->addSubImage(width, height, image, loc)) {
164 return atlas;
165 }
166
167 // If the above fails, then either we have no starting atlas, or the current
168 // one is full. Either way we need to allocate a new atlas
169
170 GrIPoint16 plot;
171 if (!fPlotMgr->newPlot(&plot)) {
172 return NULL;
173 }
174
175 GrAssert(0 == kA8_GrMaskFormat);
176 GrAssert(1 == kA565_GrMaskFormat);
177 if (NULL == fTexture[format]) {
178 GrTextureDesc desc = {
179 kDynamicUpdate_GrTextureFlagBit,
180 kNone_GrAALevel,
181 GR_ATLAS_TEXTURE_WIDTH,
182 GR_ATLAS_TEXTURE_HEIGHT,
183 maskformat2pixelconfig(format)
184 };
185 fTexture[format] = fGpu->createTexture(desc, NULL, 0);
186 if (NULL == fTexture[format]) {
187 return NULL;
188 }
189 }
190
191 GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format);
192 if (!newAtlas->addSubImage(width, height, image, loc)) {
193 delete newAtlas;
194 return NULL;
195 }
196
197 newAtlas->fNext = atlas;
198 return newAtlas;
199 }
200
freePlot(int x,int y)201 void GrAtlasMgr::freePlot(int x, int y) {
202 GrAssert(fPlotMgr->isBusy(x, y));
203 fPlotMgr->freePlot(x, y);
204 }
205
206
207