blob: 646c213b8675a738aa190daeece4ebc2088f49ab [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
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000038#ifdef SK_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +000039 static int gCounter;
40#endif
41
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000042// for testing
43#define FONT_CACHE_STATS 0
44#if FONT_CACHE_STATS
45static int g_UploadCount = 0;
46#endif
47
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000048GrPlot::GrPlot() : fDrawToken(NULL, 0)
49 , fNext(NULL)
50 , fTexture(NULL)
51 , fAtlasMgr(NULL)
52 , fBytesPerPixel(1)
53{
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000054 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH,
55 GR_ATLAS_HEIGHT);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000056 fOffset.set(0, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +000057}
58
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000059GrPlot::~GrPlot() {
reed@google.comac10a2d2010-12-22 21:39:39 +000060 delete fRects;
reed@google.comac10a2d2010-12-22 21:39:39 +000061}
62
robertphillips@google.com8b169312013-10-15 17:47:36 +000063static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) {
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000064 loc->fX += offset.fX * GR_ATLAS_WIDTH;
65 loc->fY += offset.fY * GR_ATLAS_HEIGHT;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000066}
67
robertphillips@google.com8b169312013-10-15 17:47:36 +000068static inline uint8_t* zero_fill(uint8_t* ptr, size_t count) {
69 sk_bzero(ptr, count);
70 return ptr + count;
reed@google.com98539c62011-03-15 15:40:16 +000071}
72
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000073bool GrPlot::addSubImage(int width, int height, const void* image,
reed@google.comac10a2d2010-12-22 21:39:39 +000074 GrIPoint16* loc) {
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000075 if (!fRects->addRect(width, height, loc)) {
reed@google.comac10a2d2010-12-22 21:39:39 +000076 return false;
77 }
78
bsalomon@google.com3582bf92011-06-30 21:32:31 +000079 SkAutoSMalloc<1024> storage;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000080 adjust_for_offset(loc, fOffset);
bsalomon@google.com6f379512011-11-16 20:36:03 +000081 GrContext* context = fTexture->getContext();
bsalomon@google.com0342a852012-08-20 19:22:38 +000082 // We pass the flag that does not force a flush. We assume our caller is
83 // smart and hasn't referenced the part of the texture we're about to update
84 // since the last flush.
85 context->writeTexturePixels(fTexture,
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000086 loc->fX, loc->fY, width, height,
bsalomon@google.com0342a852012-08-20 19:22:38 +000087 fTexture->config(), image, 0,
88 GrContext::kDontFlush_PixelOpsFlag);
reed@google.comac10a2d2010-12-22 21:39:39 +000089
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000090#if FONT_CACHE_STATS
91 ++g_UploadCount;
92#endif
93
reed@google.comac10a2d2010-12-22 21:39:39 +000094 return true;
95}
96
97///////////////////////////////////////////////////////////////////////////////
98
commit-bot@chromium.org95294412013-09-26 15:28:40 +000099GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000100 fGpu = gpu;
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000101 fPixelConfig = config;
reed@google.comac10a2d2010-12-22 21:39:39 +0000102 gpu->ref();
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000103 fTexture = NULL;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000104
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000105 // set up allocated plots
robertphillips@google.com8b169312013-10-15 17:47:36 +0000106 size_t bpp = GrBytesPerPixel(fPixelConfig);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000107 fPlots = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT));
108 fFreePlots = NULL;
109 GrPlot* currPlot = fPlots;
110 for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) {
111 for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) {
112 currPlot->fAtlasMgr = this;
113 currPlot->fOffset.set(x, y);
114 currPlot->fBytesPerPixel = bpp;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000115
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000116 // add to free list
117 currPlot->fNext = fFreePlots;
118 fFreePlots = currPlot;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000119
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000120 ++currPlot;
121 }
122 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000123}
124
125GrAtlasMgr::~GrAtlasMgr() {
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000126 SkSafeUnref(fTexture);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000127 SkDELETE_ARRAY(fPlots);
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000128
reed@google.comac10a2d2010-12-22 21:39:39 +0000129 fGpu->unref();
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000130#if FONT_CACHE_STATS
131 GrPrintf("Num uploads: %d\n", g_UploadCount);
132#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000133}
134
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000135GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
136 int width, int height, const void* image,
137 GrIPoint16* loc) {
138 // iterate through entire plot list, see if we can find a hole
139 GrPlot* plotIter = atlas->fPlots;
140 while (plotIter) {
141 if (plotIter->addSubImage(width, height, image, loc)) {
142 return plotIter;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000143 }
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000144 plotIter = plotIter->fNext;
reed@google.comac10a2d2010-12-22 21:39:39 +0000145 }
146
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000147 // If the above fails, then either we have no starting plot, or the current
148 // plot list is full. Either way we need to allocate a new plot
149 GrPlot* newPlot = this->allocPlot();
150 if (NULL == newPlot) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000151 return NULL;
152 }
153
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000154 if (NULL == fTexture) {
bsalomon@google.com95ed55a2013-01-24 14:46:47 +0000155 // TODO: Update this to use the cache rather than directly creating a texture.
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000156 GrTextureDesc desc;
157 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
158 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH;
159 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT;
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000160 desc.fConfig = fPixelConfig;
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000161
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000162 fTexture = fGpu->createTexture(desc, NULL, 0);
163 if (NULL == fTexture) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000164 return NULL;
165 }
166 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000167 // be sure to set texture for fast lookup
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000168 newPlot->fTexture = fTexture;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000169
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000170 if (!newPlot->addSubImage(width, height, image, loc)) {
171 this->freePlot(newPlot);
reed@google.comac10a2d2010-12-22 21:39:39 +0000172 return NULL;
173 }
174
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000175 // new plot, put at head
176 newPlot->fNext = atlas->fPlots;
177 atlas->fPlots = newPlot;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000178
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000179 return newPlot;
reed@google.comac10a2d2010-12-22 21:39:39 +0000180}
181
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000182bool GrAtlasMgr::removeUnusedPlots(GrAtlas* atlas) {
commit-bot@chromium.org03e3e892013-10-02 18:19:17 +0000183
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000184 // GrPlot** is used so that the head element can be easily
185 // modified when the first element is deleted
186 GrPlot** plotRef = &atlas->fPlots;
187 GrPlot* plot = atlas->fPlots;
188 bool removed = false;
189 while (NULL != plot) {
190 if (plot->drawToken().isIssued()) {
191 *plotRef = plot->fNext;
192 this->freePlot(plot);
193 plot = *plotRef;
194 removed = true;
195 } else {
196 plotRef = &plot->fNext;
197 plot = plot->fNext;
198 }
199 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000200
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000201 return removed;
202}
203
204void GrAtlasMgr::deletePlotList(GrPlot* plot) {
205 while (NULL != plot) {
206 GrPlot* next = plot->fNext;
207 this->freePlot(plot);
208 plot = next;
209 }
210}
211
212GrPlot* GrAtlasMgr::allocPlot() {
213 if (NULL == fFreePlots) {
214 return NULL;
215 } else {
216 GrPlot* alloc = fFreePlots;
217 fFreePlots = alloc->fNext;
218#ifdef SK_DEBUG
219// GrPrintf(" GrPlot %p [%d %d] %d\n", this, alloc->fOffset.fX, alloc->fOffset.fY, gCounter);
220 gCounter += 1;
221#endif
222 return alloc;
223 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000224
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000225}
226
227void GrAtlasMgr::freePlot(GrPlot* plot) {
228 SkASSERT(this == plot->fAtlasMgr);
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000229
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000230 plot->fRects->reset();
231 plot->fNext = fFreePlots;
232 fFreePlots = plot;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000233
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000234#ifdef SK_DEBUG
235 --gCounter;
236// GrPrintf("~GrPlot %p [%d %d] %d\n", this, plot->fOffset.fX, plot->fOffset.fY, gCounter);
237#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000238}
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000239
240SkISize GrAtlas::getSize() const {
241 return SkISize::Make(GR_ATLAS_TEXTURE_WIDTH, GR_ATLAS_TEXTURE_HEIGHT);
242}