gfx/skia/trunk/src/gpu/GrAtlas.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:066ec2b80e73
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 // for testing
39 #define FONT_CACHE_STATS 0
40 #if FONT_CACHE_STATS
41 static int g_UploadCount = 0;
42 #endif
43
44 GrPlot::GrPlot() : fDrawToken(NULL, 0)
45 , fTexture(NULL)
46 , fAtlasMgr(NULL)
47 , fBytesPerPixel(1)
48 {
49 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH,
50 GR_ATLAS_HEIGHT);
51 fOffset.set(0, 0);
52 }
53
54 GrPlot::~GrPlot() {
55 delete fRects;
56 }
57
58 static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) {
59 loc->fX += offset.fX * GR_ATLAS_WIDTH;
60 loc->fY += offset.fY * GR_ATLAS_HEIGHT;
61 }
62
63 bool GrPlot::addSubImage(int width, int height, const void* image,
64 GrIPoint16* loc) {
65 if (!fRects->addRect(width, height, loc)) {
66 return false;
67 }
68
69 SkAutoSMalloc<1024> storage;
70 adjust_for_offset(loc, fOffset);
71 GrContext* context = fTexture->getContext();
72 // We pass the flag that does not force a flush. We assume our caller is
73 // smart and hasn't referenced the part of the texture we're about to update
74 // since the last flush.
75 context->writeTexturePixels(fTexture,
76 loc->fX, loc->fY, width, height,
77 fTexture->config(), image, 0,
78 GrContext::kDontFlush_PixelOpsFlag);
79
80 #if FONT_CACHE_STATS
81 ++g_UploadCount;
82 #endif
83
84 return true;
85 }
86
87 void GrPlot::resetRects() {
88 SkASSERT(NULL != fRects);
89 fRects->reset();
90 }
91
92 ///////////////////////////////////////////////////////////////////////////////
93
94 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) {
95 fGpu = gpu;
96 fPixelConfig = config;
97 gpu->ref();
98 fTexture = NULL;
99
100 // set up allocated plots
101 size_t bpp = GrBytesPerPixel(fPixelConfig);
102 fPlotArray = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT));
103
104 GrPlot* currPlot = fPlotArray;
105 for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) {
106 for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) {
107 currPlot->fAtlasMgr = this;
108 currPlot->fOffset.set(x, y);
109 currPlot->fBytesPerPixel = bpp;
110
111 // build LRU list
112 fPlotList.addToHead(currPlot);
113 ++currPlot;
114 }
115 }
116 }
117
118 GrAtlasMgr::~GrAtlasMgr() {
119 SkSafeUnref(fTexture);
120 SkDELETE_ARRAY(fPlotArray);
121
122 fGpu->unref();
123 #if FONT_CACHE_STATS
124 GrPrintf("Num uploads: %d\n", g_UploadCount);
125 #endif
126 }
127
128 void GrAtlasMgr::moveToHead(GrPlot* plot) {
129 if (fPlotList.head() == plot) {
130 return;
131 }
132
133 fPlotList.remove(plot);
134 fPlotList.addToHead(plot);
135 };
136
137 GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
138 int width, int height, const void* image,
139 GrIPoint16* loc) {
140 // iterate through entire plot list for this atlas, see if we can find a hole
141 // last one was most recently added and probably most empty
142 for (int i = atlas->fPlots.count()-1; i >= 0; --i) {
143 GrPlot* plot = atlas->fPlots[i];
144 if (plot->addSubImage(width, height, image, loc)) {
145 this->moveToHead(plot);
146 return plot;
147 }
148 }
149
150 // before we get a new plot, make sure we have a backing texture
151 if (NULL == fTexture) {
152 // TODO: Update this to use the cache rather than directly creating a texture.
153 GrTextureDesc desc;
154 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
155 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH;
156 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT;
157 desc.fConfig = fPixelConfig;
158
159 fTexture = fGpu->createTexture(desc, NULL, 0);
160 if (NULL == fTexture) {
161 return NULL;
162 }
163 }
164
165 // now look through all allocated plots for one we can share, in MRU order
166 GrPlotList::Iter plotIter;
167 plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart);
168 GrPlot* plot;
169 while (NULL != (plot = plotIter.get())) {
170 // make sure texture is set for quick lookup
171 plot->fTexture = fTexture;
172 if (plot->addSubImage(width, height, image, loc)) {
173 this->moveToHead(plot);
174 // new plot for atlas, put at end of array
175 *(atlas->fPlots.append()) = plot;
176 return plot;
177 }
178 plotIter.next();
179 }
180
181 // If the above fails, then the current plot list has no room
182 return NULL;
183 }
184
185 bool GrAtlasMgr::removePlot(GrAtlas* atlas, const GrPlot* plot) {
186 // iterate through plot list for this atlas
187 int count = atlas->fPlots.count();
188 for (int i = 0; i < count; ++i) {
189 if (plot == atlas->fPlots[i]) {
190 atlas->fPlots.remove(i);
191 return true;
192 }
193 }
194
195 return false;
196 }
197
198 // get a plot that's not being used by the current draw
199 GrPlot* GrAtlasMgr::getUnusedPlot() {
200 GrPlotList::Iter plotIter;
201 plotIter.init(fPlotList, GrPlotList::Iter::kTail_IterStart);
202 GrPlot* plot;
203 while (NULL != (plot = plotIter.get())) {
204 if (plot->drawToken().isIssued()) {
205 return plot;
206 }
207 plotIter.prev();
208 }
209
210 return NULL;
211 }
212
213 SkISize GrAtlas::getSize() const {
214 return SkISize::Make(GR_ATLAS_TEXTURE_WIDTH, GR_ATLAS_TEXTURE_HEIGHT);
215 }

mercurial