• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * 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.
7  */
8 
9 #include "GrAtlas.h"
10 #include "GrContext.h"
11 #include "GrGpu.h"
12 #include "GrRectanizer.h"
13 
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 
28 #define GR_ATLAS_WIDTH  256
29 #define GR_ATLAS_HEIGHT 256
30 
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 
40 #ifdef SK_DEBUG
41     static int gCounter;
42 #endif
43 
44 // for testing
45 #define FONT_CACHE_STATS 0
46 #if FONT_CACHE_STATS
47 static int g_UploadCount = 0;
48 #endif
49 
GrPlot()50 GrPlot::GrPlot() : fDrawToken(NULL, 0)
51                  , fNext(NULL)
52                  , fTexture(NULL)
53                  , fAtlasMgr(NULL)
54                  , fBytesPerPixel(1)
55 {
56     fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
57                                    GR_ATLAS_HEIGHT - BORDER);
58     fOffset.set(0, 0);
59 }
60 
~GrPlot()61 GrPlot::~GrPlot() {
62     delete fRects;
63 }
64 
adjust_for_offset(GrIPoint16 * loc,const GrIPoint16 & offset)65 static inline 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;
68 }
69 
zero_fill(uint8_t * ptr,size_t count)70 static inline uint8_t* zero_fill(uint8_t* ptr, size_t count) {
71     sk_bzero(ptr, count);
72     return ptr + count;
73 }
74 
addSubImage(int width,int height,const void * image,GrIPoint16 * loc)75 bool GrPlot::addSubImage(int width, int height, const void* image,
76                           GrIPoint16* loc) {
77     if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
78         return false;
79     }
80 
81     SkAutoSMalloc<1024> storage;
82     int dstW = width + 2*BORDER;
83     int dstH = height + 2*BORDER;
84     if (BORDER) {
85         const size_t dstRB = dstW * fBytesPerPixel;
86         uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB);
87         sk_bzero(dst, dstRB);                // zero top row
88         dst += dstRB;
89         for (int y = 0; y < height; y++) {
90             dst = zero_fill(dst, fBytesPerPixel);   // zero left edge
91             memcpy(dst, image, width * fBytesPerPixel);
92             dst += width * fBytesPerPixel;
93             dst = zero_fill(dst, fBytesPerPixel);   // zero right edge
94             image = (const void*)((const char*)image + width * fBytesPerPixel);
95         }
96         sk_bzero(dst, dstRB);                // zero bottom row
97         image = storage.get();
98     }
99     adjust_for_offset(loc, fOffset);
100     GrContext* context = fTexture->getContext();
101     // We pass the flag that does not force a flush. We assume our caller is
102     // smart and hasn't referenced the part of the texture we're about to update
103     // since the last flush.
104     context->writeTexturePixels(fTexture,
105                                 loc->fX, loc->fY, dstW, dstH,
106                                 fTexture->config(), image, 0,
107                                 GrContext::kDontFlush_PixelOpsFlag);
108 
109     // now tell the caller to skip the top/left BORDER
110     loc->fX += BORDER;
111     loc->fY += BORDER;
112 
113 #if FONT_CACHE_STATS
114     ++g_UploadCount;
115 #endif
116 
117     return true;
118 }
119 
120 ///////////////////////////////////////////////////////////////////////////////
121 
GrAtlasMgr(GrGpu * gpu,GrPixelConfig config)122 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) {
123     fGpu = gpu;
124     fPixelConfig = config;
125     gpu->ref();
126     fTexture = NULL;
127 
128     // set up allocated plots
129     size_t bpp = GrBytesPerPixel(fPixelConfig);
130     fPlots = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT));
131     fFreePlots = NULL;
132     GrPlot* currPlot = fPlots;
133     for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) {
134         for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) {
135             currPlot->fAtlasMgr = this;
136             currPlot->fOffset.set(x, y);
137             currPlot->fBytesPerPixel = bpp;
138 
139             // add to free list
140             currPlot->fNext = fFreePlots;
141             fFreePlots = currPlot;
142 
143             ++currPlot;
144         }
145     }
146 }
147 
~GrAtlasMgr()148 GrAtlasMgr::~GrAtlasMgr() {
149     SkSafeUnref(fTexture);
150     SkDELETE_ARRAY(fPlots);
151 
152     fGpu->unref();
153 #if FONT_CACHE_STATS
154       GrPrintf("Num uploads: %d\n", g_UploadCount);
155 #endif
156 }
157 
addToAtlas(GrAtlas * atlas,int width,int height,const void * image,GrIPoint16 * loc)158 GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
159                                int width, int height, const void* image,
160                                GrIPoint16* loc) {
161     // iterate through entire plot list, see if we can find a hole
162     GrPlot* plotIter = atlas->fPlots;
163     while (plotIter) {
164         if (plotIter->addSubImage(width, height, image, loc)) {
165             return plotIter;
166         }
167         plotIter = plotIter->fNext;
168     }
169 
170     // If the above fails, then either we have no starting plot, or the current
171     // plot list is full. Either way we need to allocate a new plot
172     GrPlot* newPlot = this->allocPlot();
173     if (NULL == newPlot) {
174         return NULL;
175     }
176 
177     if (NULL == fTexture) {
178         // TODO: Update this to use the cache rather than directly creating a texture.
179         GrTextureDesc desc;
180         desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
181         desc.fWidth = GR_ATLAS_TEXTURE_WIDTH;
182         desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT;
183         desc.fConfig = fPixelConfig;
184 
185         fTexture = fGpu->createTexture(desc, NULL, 0);
186         if (NULL == fTexture) {
187             return NULL;
188         }
189     }
190     // be sure to set texture for fast lookup
191     newPlot->fTexture = fTexture;
192 
193     if (!newPlot->addSubImage(width, height, image, loc)) {
194         this->freePlot(newPlot);
195         return NULL;
196     }
197 
198     // new plot, put at head
199     newPlot->fNext = atlas->fPlots;
200     atlas->fPlots = newPlot;
201 
202     return newPlot;
203 }
204 
removeUnusedPlots(GrAtlas * atlas)205 bool GrAtlasMgr::removeUnusedPlots(GrAtlas* atlas) {
206 
207     // GrPlot** is used so that the head element can be easily
208     // modified when the first element is deleted
209     GrPlot** plotRef = &atlas->fPlots;
210     GrPlot* plot = atlas->fPlots;
211     bool removed = false;
212     while (NULL != plot) {
213         if (plot->drawToken().isIssued()) {
214             *plotRef = plot->fNext;
215             this->freePlot(plot);
216             plot = *plotRef;
217             removed = true;
218         } else {
219             plotRef = &plot->fNext;
220             plot = plot->fNext;
221         }
222     }
223 
224     return removed;
225 }
226 
deletePlotList(GrPlot * plot)227 void GrAtlasMgr::deletePlotList(GrPlot* plot) {
228     while (NULL != plot) {
229         GrPlot* next = plot->fNext;
230         this->freePlot(plot);
231         plot = next;
232     }
233 }
234 
allocPlot()235 GrPlot* GrAtlasMgr::allocPlot() {
236     if (NULL == fFreePlots) {
237         return NULL;
238     } else {
239         GrPlot* alloc = fFreePlots;
240         fFreePlots = alloc->fNext;
241 #ifdef SK_DEBUG
242 //        GrPrintf(" GrPlot %p [%d %d] %d\n", this, alloc->fOffset.fX, alloc->fOffset.fY, gCounter);
243         gCounter += 1;
244 #endif
245         return alloc;
246     }
247 
248 }
249 
freePlot(GrPlot * plot)250 void GrAtlasMgr::freePlot(GrPlot* plot) {
251     SkASSERT(this == plot->fAtlasMgr);
252 
253     plot->fRects->reset();
254     plot->fNext = fFreePlots;
255     fFreePlots = plot;
256 
257 #ifdef SK_DEBUG
258     --gCounter;
259 //    GrPrintf("~GrPlot %p [%d %d] %d\n", this, plot->fOffset.fX, plot->fOffset.fY, gCounter);
260 #endif
261 }
262