OLD | NEW |
---|---|
(Empty) | |
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 "GrBatchAtlas.h" | |
10 #include "GrBatchTarget.h" | |
11 #include "GrGpu.h" | |
12 #include "GrRectanizer.h" | |
13 #include "GrTracing.h" | |
14 | |
15 /////////////////////////////////////////////////////////////////////////////// | |
16 | |
17 static GrBatchAtlas::AtlasID create_id(int id, int generation) { | |
18 // Generation ID can roll over because we only check for equality | |
19 SkASSERT(id < (1 << 16)); | |
20 return id << 16 | generation; | |
21 } | |
22 | |
23 // for testing | |
24 #define FONT_CACHE_STATS 0 | |
bsalomon
2015/03/06 16:34:59
ATLAS_STAST?
joshualitt
2015/03/09 19:45:14
Acknowledged.
| |
25 #if FONT_CACHE_STATS | |
26 static int g_UploadCount = 0; | |
27 #endif | |
28 | |
29 GrBatchPlot::GrBatchPlot() | |
30 : fLastUpload(0) | |
31 , fLastRef(0) | |
32 , fID(-1) | |
33 , fGeneration(-1) | |
34 , fPlotData(NULL) | |
35 , fPlotWidth(0) | |
36 , fPlotHeight(0) | |
37 , fX(0) | |
38 , fY(0) | |
39 , fGpu(NULL) | |
40 , fTexture(NULL) | |
41 , fRects(NULL) | |
42 , fAtlas(NULL) | |
43 , fBytesPerPixel(1) | |
44 #ifdef SK_DEBUG | |
45 , fDirty(false) | |
46 #endif | |
47 { | |
48 fOffset.set(0, 0); | |
49 } | |
50 | |
51 GrBatchPlot::~GrBatchPlot() { | |
52 SkDELETE_ARRAY(fPlotData); | |
53 fPlotData = NULL; | |
54 delete fRects; | |
55 } | |
56 | |
57 void GrBatchPlot::init(GrGpu* gpu, GrBatchAtlas* atlas, GrTexture* texture, int id, | |
58 uint32_t generation, | |
59 int offX, int offY, | |
60 int width, int height, | |
61 size_t bpp) { | |
62 fID = id; | |
63 fGeneration = generation; | |
64 fPlotWidth = width; | |
65 fPlotHeight = height; | |
66 fX = offX; | |
67 fY = offY; | |
68 fRects = GrRectanizer::Factory(width, height); | |
69 fGpu = gpu; | |
70 fAtlas = atlas; | |
71 fOffset.set(offX * width, offY * height); | |
72 fBytesPerPixel = bpp; | |
73 fPlotData = NULL; | |
74 fDirtyRect.setEmpty(); | |
75 SkDEBUGCODE(fDirty = false;) | |
76 fTexture = texture; | |
77 | |
78 // allocate backing store | |
79 fPlotData = SkNEW_ARRAY(unsigned char, fBytesPerPixel * width * height); | |
80 memset(fPlotData, 0, fBytesPerPixel * width * height); | |
81 } | |
82 | |
83 static inline void adjust_for_offset(SkIPoint16* loc, const SkIPoint16& offset) { | |
84 loc->fX += offset.fX; | |
85 loc->fY += offset.fY; | |
86 } | |
87 | |
88 bool GrBatchPlot::addSubImage(int width, int height, const void* image, SkIPoint 16* loc) { | |
89 if (!fRects->addRect(width, height, loc)) { | |
90 return false; | |
91 } | |
92 | |
93 SkASSERT(fPlotData); | |
94 const unsigned char* imagePtr = (const unsigned char*)image; | |
95 // point ourselves at the right starting spot | |
96 unsigned char* dataPtr = fPlotData; | |
97 dataPtr += fBytesPerPixel * fPlotWidth * loc->fY; | |
98 dataPtr += fBytesPerPixel * loc->fX; | |
99 // copy into the data buffer | |
100 for (int i = 0; i < height; ++i) { | |
101 memcpy(dataPtr, imagePtr, fBytesPerPixel * width); | |
102 dataPtr += fBytesPerPixel * fPlotWidth; | |
103 imagePtr += fBytesPerPixel * width; | |
104 } | |
105 | |
106 fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height); | |
107 adjust_for_offset(loc, fOffset); | |
108 SkDEBUGCODE(fDirty = true;) | |
109 | |
110 #if FONT_CACHE_STATS | |
111 ++g_UploadCount; | |
112 #endif | |
113 | |
114 return true; | |
115 } | |
116 | |
117 void GrBatchPlot::uploadToTexture() { | |
118 // We should only be issuing uploads if we are in fact dirty | |
119 SkASSERT(fDirty); | |
120 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "GrPlot::uploadToTexture "); | |
bsalomon
2015/03/06 16:34:59
update string?
joshualitt
2015/03/09 19:45:14
Acknowledged.
| |
121 SkASSERT(fTexture); | |
122 size_t rowBytes = fBytesPerPixel * fRects->width(); | |
123 const unsigned char* dataPtr = fPlotData; | |
124 dataPtr += rowBytes * fDirtyRect.fTop; | |
125 dataPtr += fBytesPerPixel * fDirtyRect.fLeft; | |
126 fGpu->writeTexturePixels(fTexture, | |
bsalomon
2015/03/06 16:34:59
I think we really need a constrained API for the u
joshualitt
2015/03/09 19:45:14
Acknowledged.
| |
127 fOffset.fX + fDirtyRect.fLeft, fOffset.fY + fDirtyR ect.fTop, | |
128 fDirtyRect.width(), fDirtyRect.height(), | |
129 fTexture->config(), dataPtr, rowBytes); | |
130 fDirtyRect.setEmpty(); | |
131 SkDEBUGCODE(fDirty = false;) | |
132 } | |
133 | |
134 void GrBatchPlot::resetRects() { | |
135 SkASSERT(fRects); | |
136 fRects->reset(); | |
137 fGeneration++; | |
138 | |
139 // zero out the plot | |
140 SkASSERT(fPlotData); | |
141 memset(fPlotData, 0, fBytesPerPixel * fPlotWidth * fPlotHeight); | |
142 | |
143 fDirtyRect.setEmpty(); | |
144 SkDEBUGCODE(fDirty = false;) | |
145 } | |
146 | |
147 /////////////////////////////////////////////////////////////////////////////// | |
148 | |
149 GrBatchAtlas::GrBatchAtlas(GrGpu* gpu, GrTexture* texture, int numPlotsX, int nu mPlotsY) | |
150 : fGpu(gpu) | |
151 , fTexture(texture) | |
152 , fNumPlotsX(numPlotsX) | |
153 , fNumPlotsY(numPlotsY) | |
154 , fPlotWidth(texture->width() / numPlotsX) | |
155 , fPlotHeight(texture->height() / numPlotsY) { | |
156 SkASSERT(fPlotWidth * fNumPlotsX == texture->width()); | |
157 SkASSERT(fPlotHeight * fNumPlotsY == texture->height()); | |
158 | |
159 // We currently do not support compressed atlases... | |
160 SkASSERT(!GrPixelConfigIsCompressed(texture->desc().fConfig)); | |
161 | |
162 // set up allocated plots | |
163 fBPP = GrBytesPerPixel(texture->desc().fConfig); | |
164 fPlotArray = SkNEW_ARRAY(SkAutoTUnref<GrBatchPlot>, (fNumPlotsX * fNumPlotsY )); | |
165 | |
166 SkAutoTUnref<GrBatchPlot>* currPlot = fPlotArray; | |
167 for (int y = fNumPlotsY - 1, r = 0; y >= 0; --y, ++r) { | |
168 for (int x = fNumPlotsX - 1, c = 0; x >= 0; --x, ++c) { | |
169 int id = r * fNumPlotsX + c; | |
170 currPlot->reset(SkNEW(GrBatchPlot)); | |
171 (*currPlot)->init(fGpu, this, texture, id, 0, x, y, fPlotWidth, fPlo tHeight, fBPP); | |
172 | |
173 // build LRU list | |
174 fPlotList.addToHead(currPlot->get()); | |
175 ++currPlot; | |
176 } | |
177 } | |
178 } | |
179 | |
180 GrBatchAtlas::~GrBatchAtlas() { | |
181 SkSafeUnref(fTexture); | |
182 SkDELETE_ARRAY(fPlotArray); | |
183 | |
184 #if FONT_CACHE_STATS | |
185 SkDebugf("Num uploads: %d\n", g_UploadCount); | |
186 #endif | |
187 } | |
188 | |
189 void GrBatchAtlas::makeMRU(GrBatchPlot* plot) { | |
190 if (fPlotList.head() == plot) { | |
191 return; | |
192 } | |
193 | |
194 fPlotList.remove(plot); | |
195 fPlotList.addToHead(plot); | |
196 } | |
197 | |
198 | |
199 inline void GrBatchAtlas::updatePlot(GrBatchTarget* batchTarget, AtlasID* id, Gr BatchPlot* plot) { | |
200 this->makeMRU(plot); | |
201 | |
202 // if we've already issued the last plot upload, then we have to issue a new one. Otherwise we | |
203 // can just piggyback | |
bsalomon
2015/03/06 16:34:59
I understand this but might not in a few months...
joshualitt
2015/03/09 19:45:15
Acknowledged.
| |
204 if (batchTarget->isIssued(plot->lastUploadToken())) { | |
205 plot->setLastUploadToken(batchTarget->asapToken()); | |
206 batchTarget->update(GrPlotUpdater(plot)); | |
207 } | |
208 *id = create_id(plot->id(), plot->generation()); | |
209 } | |
210 | |
211 bool GrBatchAtlas::addToAtlas(AtlasID* id, GrBatchTarget* batchTarget, | |
212 int width, int height, const void* image, SkIPoint 16* loc) { | |
213 // We should already have a texture, TODO clean this up | |
214 SkASSERT(fTexture && width < fPlotWidth && height < fPlotHeight); | |
215 | |
216 // now look through all allocated plots for one we can share, in MRU order | |
217 GrBatchPlotList::Iter plotIter; | |
218 plotIter.init(fPlotList, GrBatchPlotList::Iter::kHead_IterStart); | |
219 GrBatchPlot* plot; | |
220 while ((plot = plotIter.get())) { | |
221 if (plot->addSubImage(width, height, image, loc)) { | |
222 this->updatePlot(batchTarget, id, plot); | |
223 return true; | |
224 } | |
225 plotIter.next(); | |
226 } | |
227 | |
228 // If the above fails, then find an unused LRU spot | |
229 plotIter.init(fPlotList, GrBatchPlotList::Iter::kTail_IterStart); | |
230 while ((plot = plotIter.get())) { | |
231 if (batchTarget->isIssued(plot->lastRefToken())) { | |
232 plot->resetRects(); | |
233 SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, l oc); | |
234 SkASSERT(verify); | |
235 this->updatePlot(batchTarget, id, plot); | |
236 return true; | |
237 } | |
238 plotIter.prev(); | |
239 } | |
240 | |
241 // get LRU, queue up an upload. However, if our plot was referenced in this draw, then we can't | |
Jvsquare
2015/03/06 15:45:36
I don't see where we are queuing up an upload here
joshualitt
2015/03/09 19:45:14
Acknowledged.
| |
242 // reuse it. We return false to force the caller to start a new draw | |
243 plotIter.init(fPlotList, GrBatchPlotList::Iter::kTail_IterStart); | |
244 plot = plotIter.get(); | |
245 SkASSERT(plot); | |
246 if (plot->lastRefToken() == batchTarget->currentToken()) { | |
247 return false; | |
248 } | |
249 | |
250 // Now we have to remove the old plot from the plot list and the plot array and add the new plot | |
251 int plotID = plot->id(); | |
252 int x = plot->x(); | |
253 int y = plot->y(); | |
254 int generation = plot->generation(); | |
255 | |
256 fPlotList.remove(plot); | |
257 SkAutoTUnref<GrBatchPlot>& newPlot = fPlotArray[plot->id()]; | |
258 newPlot.reset(SkNEW(GrBatchPlot)); | |
259 newPlot->init(fGpu, this, fTexture, plotID, ++generation, x, y, fPlotWidth, fPlotHeight, fBPP); | |
260 | |
261 fPlotList.addToHead(newPlot.get()); | |
262 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc); | |
263 SkASSERT(verify); | |
264 newPlot->setLastUploadToken(batchTarget->currentToken()); | |
265 batchTarget->update(GrPlotUpdater(newPlot)); | |
bsalomon
2015/03/06 16:34:59
@Jvsquare: I think it is here.
| |
266 *id = create_id(newPlot->id(), newPlot->generation()); | |
267 return true; | |
268 } | |
269 | |
270 void GrBatchAtlas::uploadPlotsToTexture() { | |
271 GrBatchPlotList::Iter plotIter; | |
272 plotIter.init(fPlotList, GrBatchPlotList::Iter::kHead_IterStart); | |
273 GrBatchPlot* plot; | |
274 while ((plot = plotIter.get())) { | |
275 plot->uploadToTexture(); | |
276 plotIter.next(); | |
277 } | |
278 } | |
OLD | NEW |