blob: 480a3073f91b515cd41ddefdde14da4c8a043e03 [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;
reed@google.com759c16e2011-03-15 19:15:15 +000057 fTexture = mgr->getTexture(format); // we're not an owner, just a pointer
reed@google.comac10a2d2010-12-22 21:39:39 +000058 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();
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:
152 return kRGBA_8888_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,
reed@google.com98539c62011-03-15 15:40:16 +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