blob: 9784e83de906472fc4bc68451581354754fa70ee [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
reed@google.comac10a2d2010-12-22 21:39:39 +00009#include "GrAtlas.h"
bsalomon@google.com6f379512011-11-16 20:36:03 +000010#include "GrContext.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000011#include "GrGpu.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000012#include "GrRectanizer.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000013
14#if 0
15#define GR_PLOT_WIDTH 8
16#define GR_PLOT_HEIGHT 4
17#define GR_ATLAS_WIDTH 256
18#define GR_ATLAS_HEIGHT 256
19
20#define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH)
21#define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT)
22
23#else
24
25#define GR_ATLAS_TEXTURE_WIDTH 1024
26#define GR_ATLAS_TEXTURE_HEIGHT 2048
27
commit-bot@chromium.org09846a02013-10-02 17:37:59 +000028#define GR_ATLAS_WIDTH 256
29#define GR_ATLAS_HEIGHT 256
reed@google.comac10a2d2010-12-22 21:39:39 +000030
31#define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH)
32#define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT)
33
34#endif
35
36///////////////////////////////////////////////////////////////////////////////
37
38#define BORDER 1
39
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000040#ifdef SK_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +000041 static int gCounter;
42#endif
43
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000044// for testing
45#define FONT_CACHE_STATS 0
46#if FONT_CACHE_STATS
47static int g_UploadCount = 0;
48#endif
49
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000050GrPlot::GrPlot() : fDrawToken(NULL, 0)
51 , fNext(NULL)
52 , fTexture(NULL)
53 , fAtlasMgr(NULL)
54 , fBytesPerPixel(1)
55{
reed@google.comac10a2d2010-12-22 21:39:39 +000056 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
57 GR_ATLAS_HEIGHT - BORDER);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000058 fOffset.set(0, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +000059}
60
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000061GrPlot::~GrPlot() {
reed@google.comac10a2d2010-12-22 21:39:39 +000062 delete fRects;
reed@google.comac10a2d2010-12-22 21:39:39 +000063}
64
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000065static void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) {
66 loc->fX += offset.fX * GR_ATLAS_WIDTH;
67 loc->fY += offset.fY * GR_ATLAS_HEIGHT;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000068}
69
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000070static uint8_t* zero_fill(uint8_t* ptr, int count) {
reed@google.com98539c62011-03-15 15:40:16 +000071 while (--count >= 0) {
72 *ptr++ = 0;
73 }
74 return ptr;
75}
76
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000077bool GrPlot::addSubImage(int width, int height, const void* image,
reed@google.comac10a2d2010-12-22 21:39:39 +000078 GrIPoint16* loc) {
79 if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
80 return false;
81 }
82
bsalomon@google.com3582bf92011-06-30 21:32:31 +000083 SkAutoSMalloc<1024> storage;
reed@google.com98539c62011-03-15 15:40:16 +000084 int dstW = width + 2*BORDER;
85 int dstH = height + 2*BORDER;
reed@google.comac10a2d2010-12-22 21:39:39 +000086 if (BORDER) {
commit-bot@chromium.org95294412013-09-26 15:28:40 +000087 const size_t dstRB = dstW * fBytesPerPixel;
bsalomon@google.com7d4679a2011-09-02 22:06:24 +000088 uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB);
reed@google.com939ca7c2013-09-26 19:56:51 +000089 sk_bzero(dst, dstRB); // zero top row
reed@google.com98539c62011-03-15 15:40:16 +000090 dst += dstRB;
reed@google.comac10a2d2010-12-22 21:39:39 +000091 for (int y = 0; y < height; y++) {
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000092 dst = zero_fill(dst, fBytesPerPixel); // zero left edge
commit-bot@chromium.org95294412013-09-26 15:28:40 +000093 memcpy(dst, image, width * fBytesPerPixel);
94 dst += width * fBytesPerPixel;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000095 dst = zero_fill(dst, fBytesPerPixel); // zero right edge
commit-bot@chromium.org95294412013-09-26 15:28:40 +000096 image = (const void*)((const char*)image + width * fBytesPerPixel);
reed@google.comac10a2d2010-12-22 21:39:39 +000097 }
reed@google.com939ca7c2013-09-26 19:56:51 +000098 sk_bzero(dst, dstRB); // zero bottom row
reed@google.comac10a2d2010-12-22 21:39:39 +000099 image = storage.get();
100 }
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000101 adjust_for_offset(loc, fOffset);
bsalomon@google.com6f379512011-11-16 20:36:03 +0000102 GrContext* context = fTexture->getContext();
bsalomon@google.com0342a852012-08-20 19:22:38 +0000103 // We pass the flag that does not force a flush. We assume our caller is
104 // smart and hasn't referenced the part of the texture we're about to update
105 // since the last flush.
106 context->writeTexturePixels(fTexture,
107 loc->fX, loc->fY, dstW, dstH,
108 fTexture->config(), image, 0,
109 GrContext::kDontFlush_PixelOpsFlag);
reed@google.comac10a2d2010-12-22 21:39:39 +0000110
111 // now tell the caller to skip the top/left BORDER
112 loc->fX += BORDER;
113 loc->fY += BORDER;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000114
115#if FONT_CACHE_STATS
116 ++g_UploadCount;
117#endif
118
reed@google.comac10a2d2010-12-22 21:39:39 +0000119 return true;
120}
121
122///////////////////////////////////////////////////////////////////////////////
123
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000124GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000125 fGpu = gpu;
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000126 fPixelConfig = config;
reed@google.comac10a2d2010-12-22 21:39:39 +0000127 gpu->ref();
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000128 fTexture = NULL;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000129
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000130 // set up allocated plots
131 int bpp = GrBytesPerPixel(fPixelConfig);
132 fPlots = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT));
133 fFreePlots = NULL;
134 GrPlot* currPlot = fPlots;
135 for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) {
136 for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) {
137 currPlot->fAtlasMgr = this;
138 currPlot->fOffset.set(x, y);
139 currPlot->fBytesPerPixel = bpp;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000140
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000141 // add to free list
142 currPlot->fNext = fFreePlots;
143 fFreePlots = currPlot;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000144
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000145 ++currPlot;
146 }
147 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000148}
149
150GrAtlasMgr::~GrAtlasMgr() {
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000151 SkSafeUnref(fTexture);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000152 SkDELETE_ARRAY(fPlots);
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000153
reed@google.comac10a2d2010-12-22 21:39:39 +0000154 fGpu->unref();
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000155#if FONT_CACHE_STATS
156 GrPrintf("Num uploads: %d\n", g_UploadCount);
157#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000158}
159
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000160GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
161 int width, int height, const void* image,
162 GrIPoint16* loc) {
163 // iterate through entire plot list, see if we can find a hole
164 GrPlot* plotIter = atlas->fPlots;
165 while (plotIter) {
166 if (plotIter->addSubImage(width, height, image, loc)) {
167 return plotIter;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000168 }
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000169 plotIter = plotIter->fNext;
reed@google.comac10a2d2010-12-22 21:39:39 +0000170 }
171
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000172 // If the above fails, then either we have no starting plot, or the current
173 // plot list is full. Either way we need to allocate a new plot
174 GrPlot* newPlot = this->allocPlot();
175 if (NULL == newPlot) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000176 return NULL;
177 }
178
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000179 if (NULL == fTexture) {
bsalomon@google.com95ed55a2013-01-24 14:46:47 +0000180 // TODO: Update this to use the cache rather than directly creating a texture.
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000181 GrTextureDesc desc;
commit-bot@chromium.org03e3e892013-10-02 18:19:17 +0000182#ifdef SK_DEVELOPER
183 // RenderTarget so we can read the pixels to dump them
184 desc.fFlags = kDynamicUpdate_GrTextureFlagBit|kRenderTarget_GrTextureFlagBit
185 |kNoStencil_GrTextureFlagBit;
186#else
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000187 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
commit-bot@chromium.org03e3e892013-10-02 18:19:17 +0000188#endif
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000189 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH;
190 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT;
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000191 desc.fConfig = fPixelConfig;
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000192
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000193 fTexture = fGpu->createTexture(desc, NULL, 0);
194 if (NULL == fTexture) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000195 return NULL;
196 }
197 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000198 // be sure to set texture for fast lookup
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000199 newPlot->fTexture = fTexture;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000200
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000201 if (!newPlot->addSubImage(width, height, image, loc)) {
202 this->freePlot(newPlot);
reed@google.comac10a2d2010-12-22 21:39:39 +0000203 return NULL;
204 }
205
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000206 // new plot, put at head
207 newPlot->fNext = atlas->fPlots;
208 atlas->fPlots = newPlot;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000209
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000210 return newPlot;
reed@google.comac10a2d2010-12-22 21:39:39 +0000211}
212
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000213bool GrAtlasMgr::removeUnusedPlots(GrAtlas* atlas) {
commit-bot@chromium.org03e3e892013-10-02 18:19:17 +0000214
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000215 // GrPlot** is used so that the head element can be easily
216 // modified when the first element is deleted
217 GrPlot** plotRef = &atlas->fPlots;
218 GrPlot* plot = atlas->fPlots;
219 bool removed = false;
220 while (NULL != plot) {
221 if (plot->drawToken().isIssued()) {
222 *plotRef = plot->fNext;
223 this->freePlot(plot);
224 plot = *plotRef;
225 removed = true;
226 } else {
227 plotRef = &plot->fNext;
228 plot = plot->fNext;
229 }
230 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000231
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000232 return removed;
233}
234
235void GrAtlasMgr::deletePlotList(GrPlot* plot) {
236 while (NULL != plot) {
237 GrPlot* next = plot->fNext;
238 this->freePlot(plot);
239 plot = next;
240 }
241}
242
243GrPlot* GrAtlasMgr::allocPlot() {
244 if (NULL == fFreePlots) {
245 return NULL;
246 } else {
247 GrPlot* alloc = fFreePlots;
248 fFreePlots = alloc->fNext;
249#ifdef SK_DEBUG
250// GrPrintf(" GrPlot %p [%d %d] %d\n", this, alloc->fOffset.fX, alloc->fOffset.fY, gCounter);
251 gCounter += 1;
252#endif
253 return alloc;
254 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000255
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000256}
257
258void GrAtlasMgr::freePlot(GrPlot* plot) {
259 SkASSERT(this == plot->fAtlasMgr);
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000260
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000261 plot->fRects->reset();
262 plot->fNext = fFreePlots;
263 fFreePlots = plot;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000264
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000265#ifdef SK_DEBUG
266 --gCounter;
267// GrPrintf("~GrPlot %p [%d %d] %d\n", this, plot->fOffset.fX, plot->fOffset.fY, gCounter);
268#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000269}