blob: ea4949bffc8ee42762195f92ef670cf5b69cd623 [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"
reed@google.comac10a2d2010-12-22 21:39:39 +000020#include "GrRectanizer.h"
21#include "GrPlotMgr.h"
22
23#if 0
24#define GR_PLOT_WIDTH 8
25#define GR_PLOT_HEIGHT 4
26#define GR_ATLAS_WIDTH 256
27#define GR_ATLAS_HEIGHT 256
28
29#define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH)
30#define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT)
31
32#else
33
34#define GR_ATLAS_TEXTURE_WIDTH 1024
35#define GR_ATLAS_TEXTURE_HEIGHT 2048
36
37#define GR_ATLAS_WIDTH 341
38#define GR_ATLAS_HEIGHT 341
39
40#define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH)
41#define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT)
42
43#endif
44
45///////////////////////////////////////////////////////////////////////////////
46
47#define BORDER 1
48
49#if GR_DEBUG
50 static int gCounter;
51#endif
52
reed@google.com98539c62011-03-15 15:40:16 +000053GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) {
reed@google.comac10a2d2010-12-22 21:39:39 +000054 fAtlasMgr = mgr; // just a pointer, not an owner
55 fNext = NULL;
reed@google.com759c16e2011-03-15 19:15:15 +000056 fTexture = mgr->getTexture(format); // we're not an owner, just a pointer
reed@google.comac10a2d2010-12-22 21:39:39 +000057 fPlot.set(plotX, plotY);
58
59 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
60 GR_ATLAS_HEIGHT - BORDER);
61
reed@google.com98539c62011-03-15 15:40:16 +000062 fMaskFormat = format;
63
reed@google.comac10a2d2010-12-22 21:39:39 +000064#if GR_DEBUG
reed@google.com3ef80cf2011-07-05 19:09:47 +000065// GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
reed@google.comac10a2d2010-12-22 21:39:39 +000066 gCounter += 1;
67#endif
68}
69
70GrAtlas::~GrAtlas() {
71 fAtlasMgr->freePlot(fPlot.fX, fPlot.fY);
72
73 delete fRects;
74
75#if GR_DEBUG
76 --gCounter;
reed@google.com3ef80cf2011-07-05 19:09:47 +000077// GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter);
reed@google.comac10a2d2010-12-22 21:39:39 +000078#endif
79}
80
81static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) {
82 loc->fX += plot.fX * GR_ATLAS_WIDTH;
83 loc->fY += plot.fY * GR_ATLAS_HEIGHT;
84}
85
reed@google.com98539c62011-03-15 15:40:16 +000086static uint8_t* zerofill(uint8_t* ptr, int count) {
87 while (--count >= 0) {
88 *ptr++ = 0;
89 }
90 return ptr;
91}
92
reed@google.comac10a2d2010-12-22 21:39:39 +000093bool GrAtlas::addSubImage(int width, int height, const void* image,
94 GrIPoint16* loc) {
95 if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
96 return false;
97 }
98
bsalomon@google.com3582bf92011-06-30 21:32:31 +000099 SkAutoSMalloc<1024> storage;
reed@google.com98539c62011-03-15 15:40:16 +0000100 int dstW = width + 2*BORDER;
101 int dstH = height + 2*BORDER;
reed@google.comac10a2d2010-12-22 21:39:39 +0000102 if (BORDER) {
reed@google.com98539c62011-03-15 15:40:16 +0000103 const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat);
104 const size_t dstRB = dstW * bpp;
105 uint8_t* dst = (uint8_t*)storage.realloc(dstH * dstRB);
106 Gr_bzero(dst, dstRB); // zero top row
107 dst += dstRB;
reed@google.comac10a2d2010-12-22 21:39:39 +0000108 for (int y = 0; y < height; y++) {
reed@google.com98539c62011-03-15 15:40:16 +0000109 dst = zerofill(dst, bpp); // zero left edge
110 memcpy(dst, image, width * bpp);
111 dst += width * bpp;
112 dst = zerofill(dst, bpp); // zero right edge
113 image = (const void*)((const char*)image + width * bpp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000114 }
reed@google.com98539c62011-03-15 15:40:16 +0000115 Gr_bzero(dst, dstRB); // zero bottom row
reed@google.comac10a2d2010-12-22 21:39:39 +0000116 image = storage.get();
117 }
118 adjustForPlot(loc, fPlot);
junov@google.com4ee7ae52011-06-30 17:30:49 +0000119 fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000120
121 // now tell the caller to skip the top/left BORDER
122 loc->fX += BORDER;
123 loc->fY += BORDER;
124 return true;
125}
126
127///////////////////////////////////////////////////////////////////////////////
128
129GrAtlasMgr::GrAtlasMgr(GrGpu* gpu) {
130 fGpu = gpu;
131 gpu->ref();
reed@google.com759c16e2011-03-15 19:15:15 +0000132 Gr_bzero(fTexture, sizeof(fTexture));
reed@google.comac10a2d2010-12-22 21:39:39 +0000133 fPlotMgr = new GrPlotMgr(GR_PLOT_WIDTH, GR_PLOT_HEIGHT);
134}
135
136GrAtlasMgr::~GrAtlasMgr() {
reed@google.com759c16e2011-03-15 19:15:15 +0000137 for (size_t i = 0; i < GR_ARRAY_COUNT(fTexture); i++) {
138 GrSafeUnref(fTexture[i]);
139 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000140 delete fPlotMgr;
141 fGpu->unref();
142}
143
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000144static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) {
reed@google.com98539c62011-03-15 15:40:16 +0000145 switch (format) {
146 case kA8_GrMaskFormat:
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000147 return kAlpha_8_GrPixelConfig;
reed@google.com98539c62011-03-15 15:40:16 +0000148 case kA565_GrMaskFormat:
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000149 return kRGB_565_GrPixelConfig;
caryclark@google.com1eeaf0b2011-06-22 13:19:43 +0000150 case kA888_GrMaskFormat:
151 return kRGBA_8888_GrPixelConfig;
reed@google.com98539c62011-03-15 15:40:16 +0000152 default:
153 GrAssert(!"unknown maskformat");
154 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000155 return kUnknown_GrPixelConfig;
reed@google.com98539c62011-03-15 15:40:16 +0000156}
157
reed@google.comac10a2d2010-12-22 21:39:39 +0000158GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
159 int width, int height, const void* image,
reed@google.com98539c62011-03-15 15:40:16 +0000160 GrMaskFormat format,
reed@google.comac10a2d2010-12-22 21:39:39 +0000161 GrIPoint16* loc) {
reed@google.com98539c62011-03-15 15:40:16 +0000162 GrAssert(NULL == atlas || atlas->getMaskFormat() == format);
reed@google.com759c16e2011-03-15 19:15:15 +0000163
reed@google.comac10a2d2010-12-22 21:39:39 +0000164 if (atlas && atlas->addSubImage(width, height, image, loc)) {
165 return atlas;
166 }
167
168 // If the above fails, then either we have no starting atlas, or the current
169 // one is full. Either way we need to allocate a new atlas
170
171 GrIPoint16 plot;
172 if (!fPlotMgr->newPlot(&plot)) {
173 return NULL;
174 }
175
reed@google.com759c16e2011-03-15 19:15:15 +0000176 GrAssert(0 == kA8_GrMaskFormat);
177 GrAssert(1 == kA565_GrMaskFormat);
178 if (NULL == fTexture[format]) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 GrTextureDesc desc = {
180 kDynamicUpdate_GrTextureFlagBit,
181 kNone_GrAALevel,
reed@google.com98539c62011-03-15 15:40:16 +0000182 GR_ATLAS_TEXTURE_WIDTH,
reed@google.comac10a2d2010-12-22 21:39:39 +0000183 GR_ATLAS_TEXTURE_HEIGHT,
reed@google.com98539c62011-03-15 15:40:16 +0000184 maskformat2pixelconfig(format)
reed@google.comac10a2d2010-12-22 21:39:39 +0000185 };
reed@google.com759c16e2011-03-15 19:15:15 +0000186 fTexture[format] = fGpu->createTexture(desc, NULL, 0);
187 if (NULL == fTexture[format]) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000188 return NULL;
189 }
190 }
191
reed@google.com98539c62011-03-15 15:40:16 +0000192 GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format);
reed@google.comac10a2d2010-12-22 21:39:39 +0000193 if (!newAtlas->addSubImage(width, height, image, loc)) {
194 delete newAtlas;
195 return NULL;
196 }
197
198 newAtlas->fNext = atlas;
199 return newAtlas;
200}
201
202void GrAtlasMgr::freePlot(int x, int y) {
203 GrAssert(fPlotMgr->isBusy(x, y));
204 fPlotMgr->freePlot(x, y);
205}
206
reed@google.comac10a2d2010-12-22 21:39:39 +0000207