blob: a37df9c89a53ddf7dddafef4f304e75b904ca03b [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
reed@google.com98539c62011-03-15 15:40:16 +0000145static GrTexture::PixelConfig maskformat2pixelconfig(GrMaskFormat format) {
146 switch (format) {
147 case kA8_GrMaskFormat:
148 return GrTexture::kAlpha_8_PixelConfig;
149 case kA565_GrMaskFormat:
150 return GrTexture::kRGB_565_PixelConfig;
151 default:
152 GrAssert(!"unknown maskformat");
153 }
154 return GrTexture::kUnknown_PixelConfig;
155}
156
reed@google.comac10a2d2010-12-22 21:39:39 +0000157GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
158 int width, int height, const void* image,
reed@google.com98539c62011-03-15 15:40:16 +0000159 GrMaskFormat format,
reed@google.comac10a2d2010-12-22 21:39:39 +0000160 GrIPoint16* loc) {
reed@google.com98539c62011-03-15 15:40:16 +0000161 GrAssert(NULL == atlas || atlas->getMaskFormat() == format);
reed@google.com759c16e2011-03-15 19:15:15 +0000162
reed@google.comac10a2d2010-12-22 21:39:39 +0000163 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
reed@google.com759c16e2011-03-15 19:15:15 +0000175 GrAssert(0 == kA8_GrMaskFormat);
176 GrAssert(1 == kA565_GrMaskFormat);
177 if (NULL == fTexture[format]) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000178 GrGpu::TextureDesc desc = {
reed@google.com98539c62011-03-15 15:40:16 +0000179 GrGpu::kDynamicUpdate_TextureFlag,
reed@google.comac10a2d2010-12-22 21:39:39 +0000180 GrGpu::kNone_AALevel,
reed@google.com98539c62011-03-15 15:40:16 +0000181 GR_ATLAS_TEXTURE_WIDTH,
reed@google.comac10a2d2010-12-22 21:39:39 +0000182 GR_ATLAS_TEXTURE_HEIGHT,
reed@google.com98539c62011-03-15 15:40:16 +0000183 maskformat2pixelconfig(format)
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 };
reed@google.com759c16e2011-03-15 19:15:15 +0000185 fTexture[format] = fGpu->createTexture(desc, NULL, 0);
186 if (NULL == fTexture[format]) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000187 return NULL;
188 }
189 }
190
reed@google.com98539c62011-03-15 15:40:16 +0000191 GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format);
reed@google.comac10a2d2010-12-22 21:39:39 +0000192 if (!newAtlas->addSubImage(width, height, image, loc)) {
193 delete newAtlas;
194 return NULL;
195 }
196
197 newAtlas->fNext = atlas;
198 return newAtlas;
199}
200
201void GrAtlasMgr::freePlot(int x, int y) {
202 GrAssert(fPlotMgr->isBusy(x, y));
203 fPlotMgr->freePlot(x, y);
204}
205
reed@google.comac10a2d2010-12-22 21:39:39 +0000206