blob: b3340a02d985e03f0a3dbb3acaf7f09351b0a392 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
reed@google.comac10a2d2010-12-22 21:39:39 +000011#include "GrAtlas.h"
bsalomon@google.com6f379512011-11-16 20:36:03 +000012#include "GrContext.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000013#include "GrGpu.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000014#include "GrRectanizer.h"
15#include "GrPlotMgr.h"
16
17#if 0
18#define GR_PLOT_WIDTH 8
19#define GR_PLOT_HEIGHT 4
20#define GR_ATLAS_WIDTH 256
21#define GR_ATLAS_HEIGHT 256
22
23#define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH)
24#define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT)
25
26#else
27
28#define GR_ATLAS_TEXTURE_WIDTH 1024
29#define GR_ATLAS_TEXTURE_HEIGHT 2048
30
31#define GR_ATLAS_WIDTH 341
32#define GR_ATLAS_HEIGHT 341
33
34#define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH)
35#define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT)
36
37#endif
38
39///////////////////////////////////////////////////////////////////////////////
40
41#define BORDER 1
42
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000043#ifdef SK_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +000044 static int gCounter;
45#endif
46
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000047// for testing
48#define FONT_CACHE_STATS 0
49#if FONT_CACHE_STATS
50static int g_UploadCount = 0;
51#endif
52
commit-bot@chromium.org95294412013-09-26 15:28:40 +000053GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, int bpp) :
commit-bot@chromium.orga8916ff2013-08-16 15:53:46 +000054 fDrawToken(NULL, 0) {
reed@google.comac10a2d2010-12-22 21:39:39 +000055 fAtlasMgr = mgr; // just a pointer, not an owner
56 fNext = NULL;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000057
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +000058 fTexture = mgr->getTexture(); // we're not an owner, just a pointer
reed@google.comac10a2d2010-12-22 21:39:39 +000059 fPlot.set(plotX, plotY);
60
61 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
62 GR_ATLAS_HEIGHT - BORDER);
63
commit-bot@chromium.org95294412013-09-26 15:28:40 +000064 fBytesPerPixel = bpp;
reed@google.com98539c62011-03-15 15:40:16 +000065
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000066#ifdef SK_DEBUG
reed@google.com3ef80cf2011-07-05 19:09:47 +000067// GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
reed@google.comac10a2d2010-12-22 21:39:39 +000068 gCounter += 1;
69#endif
70}
71
72GrAtlas::~GrAtlas() {
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +000073 fAtlasMgr->freePlot(fPlot.fX, fPlot.fY);
reed@google.comac10a2d2010-12-22 21:39:39 +000074
75 delete fRects;
76
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000077#ifdef SK_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +000078 --gCounter;
reed@google.com3ef80cf2011-07-05 19:09:47 +000079// GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter);
reed@google.comac10a2d2010-12-22 21:39:39 +000080#endif
81}
82
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000083bool GrAtlas::RemoveUnusedAtlases(GrAtlasMgr* atlasMgr, GrAtlas** startAtlas) {
84 // GrAtlas** is used so that a pointer to the head element can be passed in and
85 // modified when the first element is deleted
86 GrAtlas** atlasRef = startAtlas;
87 GrAtlas* atlas = *startAtlas;
88 bool removed = false;
89 while (NULL != atlas) {
commit-bot@chromium.orga8916ff2013-08-16 15:53:46 +000090 if (atlas->drawToken().isIssued()) {
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000091 *atlasRef = atlas->fNext;
92 atlasMgr->deleteAtlas(atlas);
93 atlas = *atlasRef;
94 removed = true;
95 } else {
96 atlasRef = &atlas->fNext;
97 atlas = atlas->fNext;
98 }
99 }
100
101 return removed;
102}
103
reed@google.comac10a2d2010-12-22 21:39:39 +0000104static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) {
105 loc->fX += plot.fX * GR_ATLAS_WIDTH;
106 loc->fY += plot.fY * GR_ATLAS_HEIGHT;
107}
108
reed@google.com98539c62011-03-15 15:40:16 +0000109static uint8_t* zerofill(uint8_t* ptr, int count) {
110 while (--count >= 0) {
111 *ptr++ = 0;
112 }
113 return ptr;
114}
115
reed@google.comac10a2d2010-12-22 21:39:39 +0000116bool GrAtlas::addSubImage(int width, int height, const void* image,
117 GrIPoint16* loc) {
118 if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
119 return false;
120 }
121
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000122 SkAutoSMalloc<1024> storage;
reed@google.com98539c62011-03-15 15:40:16 +0000123 int dstW = width + 2*BORDER;
124 int dstH = height + 2*BORDER;
reed@google.comac10a2d2010-12-22 21:39:39 +0000125 if (BORDER) {
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000126 const size_t dstRB = dstW * fBytesPerPixel;
bsalomon@google.com7d4679a2011-09-02 22:06:24 +0000127 uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB);
reed@google.com939ca7c2013-09-26 19:56:51 +0000128 sk_bzero(dst, dstRB); // zero top row
reed@google.com98539c62011-03-15 15:40:16 +0000129 dst += dstRB;
reed@google.comac10a2d2010-12-22 21:39:39 +0000130 for (int y = 0; y < height; y++) {
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000131 dst = zerofill(dst, fBytesPerPixel); // zero left edge
132 memcpy(dst, image, width * fBytesPerPixel);
133 dst += width * fBytesPerPixel;
134 dst = zerofill(dst, fBytesPerPixel); // zero right edge
135 image = (const void*)((const char*)image + width * fBytesPerPixel);
reed@google.comac10a2d2010-12-22 21:39:39 +0000136 }
reed@google.com939ca7c2013-09-26 19:56:51 +0000137 sk_bzero(dst, dstRB); // zero bottom row
reed@google.comac10a2d2010-12-22 21:39:39 +0000138 image = storage.get();
139 }
140 adjustForPlot(loc, fPlot);
bsalomon@google.com6f379512011-11-16 20:36:03 +0000141 GrContext* context = fTexture->getContext();
bsalomon@google.com0342a852012-08-20 19:22:38 +0000142 // We pass the flag that does not force a flush. We assume our caller is
143 // smart and hasn't referenced the part of the texture we're about to update
144 // since the last flush.
145 context->writeTexturePixels(fTexture,
146 loc->fX, loc->fY, dstW, dstH,
147 fTexture->config(), image, 0,
148 GrContext::kDontFlush_PixelOpsFlag);
reed@google.comac10a2d2010-12-22 21:39:39 +0000149
150 // now tell the caller to skip the top/left BORDER
151 loc->fX += BORDER;
152 loc->fY += BORDER;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000153
154#if FONT_CACHE_STATS
155 ++g_UploadCount;
156#endif
157
reed@google.comac10a2d2010-12-22 21:39:39 +0000158 return true;
159}
160
161///////////////////////////////////////////////////////////////////////////////
162
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000163GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000164 fGpu = gpu;
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000165 fPixelConfig = config;
reed@google.comac10a2d2010-12-22 21:39:39 +0000166 gpu->ref();
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000167 fTexture = NULL;
168 fPlotMgr = SkNEW_ARGS(GrPlotMgr, (GR_PLOT_WIDTH, GR_PLOT_HEIGHT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000169}
170
171GrAtlasMgr::~GrAtlasMgr() {
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000172 SkSafeUnref(fTexture);
173 delete fPlotMgr;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000174
reed@google.comac10a2d2010-12-22 21:39:39 +0000175 fGpu->unref();
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000176#if FONT_CACHE_STATS
177 GrPrintf("Num uploads: %d\n", g_UploadCount);
178#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000179}
180
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000181GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas** atlas,
reed@google.comac10a2d2010-12-22 21:39:39 +0000182 int width, int height, const void* image,
183 GrIPoint16* loc) {
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000184 // iterate through entire atlas list, see if we can find a hole
185 GrAtlas* atlasIter = *atlas;
186 while (atlasIter) {
187 if (atlasIter->addSubImage(width, height, image, loc)) {
188 return atlasIter;
189 }
190 atlasIter = atlasIter->fNext;
reed@google.comac10a2d2010-12-22 21:39:39 +0000191 }
192
193 // If the above fails, then either we have no starting atlas, or the current
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000194 // atlas list is full. Either way we need to allocate a new atlas
reed@google.comac10a2d2010-12-22 21:39:39 +0000195
196 GrIPoint16 plot;
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000197 if (!fPlotMgr->newPlot(&plot)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000198 return NULL;
199 }
200
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000201 if (NULL == fTexture) {
bsalomon@google.com95ed55a2013-01-24 14:46:47 +0000202 // TODO: Update this to use the cache rather than directly creating a texture.
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000203 GrTextureDesc desc;
204 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
205 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH;
206 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT;
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000207 desc.fConfig = fPixelConfig;
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000208
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000209 fTexture = fGpu->createTexture(desc, NULL, 0);
210 if (NULL == fTexture) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000211 return NULL;
212 }
213 }
214
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000215 int bpp = GrBytesPerPixel(fPixelConfig);
216 GrAtlas* newAtlas = SkNEW_ARGS(GrAtlas, (this, plot.fX, plot.fY, bpp));
reed@google.comac10a2d2010-12-22 21:39:39 +0000217 if (!newAtlas->addSubImage(width, height, image, loc)) {
218 delete newAtlas;
219 return NULL;
220 }
221
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000222 // new atlas, put at head
223 newAtlas->fNext = *atlas;
224 *atlas = newAtlas;
225
reed@google.comac10a2d2010-12-22 21:39:39 +0000226 return newAtlas;
227}
228
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000229void GrAtlasMgr::freePlot(int x, int y) {
230 SkASSERT(fPlotMgr->isBusy(x, y));
231 fPlotMgr->freePlot(x, y);
reed@google.comac10a2d2010-12-22 21:39:39 +0000232}