Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(443)

Side by Side Diff: src/gpu/GrBatchAtlas.cpp

Issue 975303005: Creation of GrBatchAtlas and Distancefieldpathrenderer batch (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: one last nit Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "GrBatchAtlas.h"
9 #include "GrBatchTarget.h"
10 #include "GrGpu.h"
11 #include "GrRectanizer.h"
12 #include "GrTracing.h"
13
14 // for testing
15 #define ATLAS_STATS 0
16 #if ATLAS_STATS
17 static int g_UploadCount = 0;
18 #endif
19
20 static inline void adjust_for_offset(SkIPoint16* loc, const SkIPoint16& offset) {
21 loc->fX += offset.fX;
22 loc->fY += offset.fY;
23 }
24
25 // The backing GrTexture for a GrBatchAtlas is broken into a spatial grid of GrB atchPlots.
26 // The GrBatchPlots keep track of subimage placement via their GrRectanizer. In turn, a GrBatchPlot
27 // manages the lifetime of its data using two tokens, a last ref toke and a last upload token.
28 // Once a GrBatchPlot is "full" (i.e. there is no room for the new subimage acco rding to the
29 // GrRectanizer), it can no longer be used unless the last ref on the GrPlot has already been
30 // flushed through to the gpu.
31
32 class GrBatchPlot : public SkRefCnt {
bsalomon 2015/03/11 13:34:12 Doesn't need the Gr prefix when in a cpp
joshualitt 2015/03/11 16:03:27 Acknowledged.
33 public:
34 typedef GrDrawTarget::BatchToken BatchToken;
35 SK_DECLARE_INST_COUNT(GrBatchPlot);
36 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrBatchPlot);
37
38 // index() refers to the index of the plot in the owning GrAtlas's plot arra y. genID() is a
39 // monotonically incrementing number which is bumped every time the cpu back ing store is
40 // wiped, or when the plot itself is evicted from the atlas(ie, there is con tinuity in genID()
41 // across atlas spills)
42 int index() const { return fIndex; }
43 int genID() const { return fGenID; }
44
45 GrTexture* texture() const { return fTexture; }
46
47 bool addSubImage(int width, int height, const void* image, SkIPoint16* loc) {
bsalomon 2015/03/11 13:34:12 should this take a rowbytes? It seems like we're a
joshualitt 2015/03/11 16:03:27 might want to check I did this one right
48 if (!fRects->addRect(width, height, loc)) {
49 return false;
50 }
51
52 SkASSERT(fData);
53 const unsigned char* imagePtr = (const unsigned char*)image;
54 // point ourselves at the right starting spot
55 unsigned char* dataPtr = fData;
56 dataPtr += fBytesPerPixel * fWidth * loc->fY;
57 dataPtr += fBytesPerPixel * loc->fX;
58 // copy into the data buffer
59 for (int i = 0; i < height; ++i) {
60 memcpy(dataPtr, imagePtr, fBytesPerPixel * width);
61 dataPtr += fBytesPerPixel * fWidth;
62 imagePtr += fBytesPerPixel * width;
63 }
64
65 fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height);
66 adjust_for_offset(loc, fOffset);
67 SkDEBUGCODE(fDirty = true;)
68
69 #if ATLAS_STATS
70 ++g_UploadCount;
71 #endif
72
73 return true;
74 }
75
76 // to manage the lifetime of a plot, we use two tokens. We use last upload token to know when
77 // we can 'piggy back' uploads, ie if the last upload hasn't been flushed to gpu, we don't need
78 // to issue a new upload even if we update the cpu backing store. We use la stref to determine
79 // when we can evict a plot from the cache, ie if the last ref has already f lushed through
80 // the gpu then we can reuse the plot
81 BatchToken lastUploadToken() const { return fLastUpload; }
82 BatchToken lastRefToken() const { return fLastRef; }
83 void setLastUploadToken(BatchToken batchToken) { fLastUpload = batchToken; }
84 void setLastRefToken(BatchToken batchToken) { fLastRef = batchToken; }
85
86 void uploadToTexture(GrTextureUploader uploader) {
87 // We should only be issuing uploads if we are in fact dirty
88 SkASSERT(fDirty);
89 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "GrBatchPlot::upload ToTexture");
90 SkASSERT(fTexture);
91 size_t rowBytes = fBytesPerPixel * fRects->width();
92 const unsigned char* dataPtr = fData;
93 dataPtr += rowBytes * fDirtyRect.fTop;
94 dataPtr += fBytesPerPixel * fDirtyRect.fLeft;
95 uploader.writeTexturePixels(fTexture,
96 fOffset.fX + fDirtyRect.fLeft, fOffset.fY + fDirtyRect.fTop,
97 fDirtyRect.width(), fDirtyRect.height(),
98 fTexture->config(), dataPtr, rowBytes);
99 fDirtyRect.setEmpty();
100 SkDEBUGCODE(fDirty = false;)
101 }
102
103 void resetRects() {
104 SkASSERT(fRects);
105 fRects->reset();
106 fGenID++;
107
108 // zero out the plot
109 SkASSERT(fData);
110 memset(fData, 0, fBytesPerPixel * fWidth * fHeight);
111
112 fDirtyRect.setEmpty();
113 SkDEBUGCODE(fDirty = false;)
114 }
115
116 int x() const { return fX; }
117 int y() const { return fY; }
118
119 private:
120 GrBatchPlot()
121 : fLastUpload(0)
122 , fLastRef(0)
123 , fIndex(-1)
124 , fGenID(-1)
125 , fData(NULL)
126 , fWidth(0)
127 , fHeight(0)
128 , fX(0)
129 , fY(0)
130 , fTexture(NULL)
131 , fRects(NULL)
132 , fAtlas(NULL)
133 , fBytesPerPixel(1)
134 #ifdef SK_DEBUG
135 , fDirty(false)
136 #endif
137 {
138 fOffset.set(0, 0);
139 }
140
141 ~GrBatchPlot() {
142 SkDELETE_ARRAY(fData);
143 fData = NULL;
144 delete fRects;
145 }
146
147 void init(GrBatchAtlas* atlas, GrTexture* texture, int id, uint32_t generati on,
148 int offX, int offY, int width, int height, size_t bpp) {
149 fIndex = id;
150 fGenID = generation;
151 fWidth = width;
152 fHeight = height;
153 fX = offX;
154 fY = offY;
155 fRects = GrRectanizer::Factory(width, height);
156 fAtlas = atlas;
157 fOffset.set(offX * width, offY * height);
158 fBytesPerPixel = bpp;
159 fData = NULL;
160 fDirtyRect.setEmpty();
161 SkDEBUGCODE(fDirty = false;)
162 fTexture = texture;
163
164 // allocate backing store
165 fData = SkNEW_ARRAY(unsigned char, fBytesPerPixel * width * height);
166 memset(fData, 0, fBytesPerPixel * width * height);
167 }
168
169 BatchToken fLastUpload;
170 BatchToken fLastRef;
171
172 uint32_t fIndex;
173 uint32_t fGenID;
174 unsigned char* fData;
175 int fWidth;
176 int fHeight;
177 int fX;
178 int fY;
179 GrTexture* fTexture;
180 GrRectanizer* fRects;
181 GrBatchAtlas* fAtlas;
182 SkIPoint16 fOffset; // the offset of the plot in the backing texture
183 size_t fBytesPerPixel;
184 SkIRect fDirtyRect;
185 SkDEBUGCODE(bool fDirty;)
186
187 friend class GrBatchAtlas;
188
189 typedef SkRefCnt INHERITED;
190 };
191
192 ////////////////////////////////////////////////////////////////////////////////
193
194 class GrPlotUploader : public GrUploader {
195 public:
196 GrPlotUploader(GrBatchPlot* plot)
197 : INHERITED(plot->lastUploadToken())
198 , fPlot(SkRef(plot)) {
199 SkASSERT(plot);
200 }
201
202 void upload(GrTextureUploader uploader) SK_OVERRIDE { fPlot->uploadToTexture (uploader); }
203
204 private:
205 SkAutoTUnref<GrBatchPlot> fPlot;
206
207 typedef GrUploader INHERITED;
208 };
209
210 ///////////////////////////////////////////////////////////////////////////////
211
212 static GrBatchAtlas::AtlasID create_id(int index, int generation) {
213 // Generation ID can roll over because we only check for equality
214 SkASSERT(index < (1 << 16));
215 return generation << 16 | index;
216 }
217
218 GrBatchAtlas::GrBatchAtlas(GrTexture* texture, int numPlotsX, int numPlotsY)
219 : fTexture(texture)
220 , fNumPlotsX(numPlotsX)
221 , fNumPlotsY(numPlotsY)
222 , fPlotWidth(texture->width() / numPlotsX)
223 , fPlotHeight(texture->height() / numPlotsY) {
224 SkASSERT(fPlotWidth * fNumPlotsX == texture->width());
225 SkASSERT(fPlotHeight * fNumPlotsY == texture->height());
226
227 // We currently do not support compressed atlases...
228 SkASSERT(!GrPixelConfigIsCompressed(texture->desc().fConfig));
229
230 // set up allocated plots
231 fBPP = GrBytesPerPixel(texture->desc().fConfig);
232 fPlotArray = SkNEW_ARRAY(SkAutoTUnref<GrBatchPlot>, (fNumPlotsX * fNumPlotsY ));
233
234 SkAutoTUnref<GrBatchPlot>* currPlot = fPlotArray;
235 for (int y = fNumPlotsY - 1, r = 0; y >= 0; --y, ++r) {
236 for (int x = fNumPlotsX - 1, c = 0; x >= 0; --x, ++c) {
237 int id = r * fNumPlotsX + c;
238 currPlot->reset(SkNEW(GrBatchPlot));
239 (*currPlot)->init(this, texture, id, 0, x, y, fPlotWidth, fPlotHeigh t, fBPP);
240
241 // build LRU list
242 fPlotList.addToHead(currPlot->get());
243 ++currPlot;
244 }
245 }
246 }
247
248 GrBatchAtlas::~GrBatchAtlas() {
249 SkSafeUnref(fTexture);
250 SkDELETE_ARRAY(fPlotArray);
251
252 #if ATLAS_STATS
253 SkDebugf("Num uploads: %d\n", g_UploadCount);
254 #endif
255 }
256
257 void GrBatchAtlas::makeMRU(GrBatchPlot* plot) {
258 if (fPlotList.head() == plot) {
259 return;
260 }
261
262 fPlotList.remove(plot);
263 fPlotList.addToHead(plot);
264 }
265
266
267 inline void GrBatchAtlas::updatePlot(GrBatchTarget* batchTarget, AtlasID* id, Gr BatchPlot* plot) {
268 this->makeMRU(plot);
269
270 // If our most recent upload has already occurred then we have to insert a n ew
271 // upload. Otherwise, we already have a scheduled upload that hasn't yet ocu rred.
272 // This new update will piggy back on that previously scheduled update.
273 if (batchTarget->isIssued(plot->lastUploadToken())) {
274 plot->setLastUploadToken(batchTarget->asapToken());
275 SkAutoTUnref<GrPlotUploader> uploader(SkNEW_ARGS(GrPlotUploader, (plot)) );
276 batchTarget->upload(uploader);
277 }
278 *id = create_id(plot->index(), plot->genID());
279 }
280
281 bool GrBatchAtlas::addToAtlas(AtlasID* id, GrBatchTarget* batchTarget,
282 int width, int height, const void* image, SkIPoint 16* loc) {
283 // We should already have a texture, TODO clean this up
284 SkASSERT(fTexture && width < fPlotWidth && height < fPlotHeight);
285
286 // now look through all allocated plots for one we can share, in Most Recent ly Refed order
287 GrBatchPlotList::Iter plotIter;
288 plotIter.init(fPlotList, GrBatchPlotList::Iter::kHead_IterStart);
289 GrBatchPlot* plot;
290 while ((plot = plotIter.get())) {
291 if (plot->addSubImage(width, height, image, loc)) {
292 this->updatePlot(batchTarget, id, plot);
293 return true;
294 }
295 plotIter.next();
296 }
297
298 // If the above fails, then see if the least recently refed plot has already been flushed to the
299 // gpu
300 plotIter.init(fPlotList, GrBatchPlotList::Iter::kTail_IterStart);
301 plot = plotIter.get();
302 SkASSERT(plot);
303 if (batchTarget->isIssued(plot->lastRefToken())) {
304 plot->resetRects();
305 SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc);
306 SkASSERT(verify);
307 this->updatePlot(batchTarget, id, plot);
308 return true;
309 }
310
311 // The least recently refed plot hasn't been flushed to the gpu yet, however , if we have flushed
312 // it to the batch target than we can reuse it. Our last ref token is guara nteed to be less
313 // than or equal to the current token. If its 'less than' the current token , than we can spin
314 // off the plot(ie let the batch target manage it) and create a new plot in its place in our
315 // array. If it is equal to the currentToken, then the caller has to flush draws to the batch
316 // target so we can spin off the plot
317 if (plot->lastRefToken() == batchTarget->currentToken()) {
318 return false;
319 }
320
321 // We take an extra ref here so our plot isn't deleted when we reset its ind ex in the array.
322 plot->ref();
323 int index = plot->index();
324 int x = plot->x();
325 int y = plot->y();
326 int generation = plot->genID();
327
328 fPlotList.remove(plot);
329 SkAutoTUnref<GrBatchPlot>& newPlot = fPlotArray[plot->index()];
330 newPlot.reset(SkNEW(GrBatchPlot));
331 newPlot->init(this, fTexture, index, ++generation, x, y, fPlotWidth, fPlotHe ight, fBPP);
332
333 fPlotList.addToHead(newPlot.get());
334 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc);
335 SkASSERT(verify);
336 newPlot->setLastUploadToken(batchTarget->currentToken());
337 SkAutoTUnref<GrPlotUploader> uploader(SkNEW_ARGS(GrPlotUploader, (newPlot))) ;
338 batchTarget->upload(uploader);
339 *id = create_id(newPlot->index(), newPlot->genID());
340 plot->unref();
341 return true;
342 }
343
344 bool GrBatchAtlas::hasID(AtlasID id) {
345 int index = this->getIndexFromID(id);
bsalomon 2015/03/11 13:34:12 this is much clearer.
346 SkASSERT(index < fNumPlotsX * fNumPlotsY);
347 return fPlotArray[index]->genID() == this->getGenerationFromID(id);
348 }
349
350 void GrBatchAtlas::setLastRefToken(AtlasID id, BatchToken batchToken) {
351 SkASSERT(this->hasID(id));
352 int index = this->getIndexFromID(id);
353 this->makeMRU(fPlotArray[index]);
354 fPlotArray[index]->setLastRefToken(batchToken);
355 }
356
357 #ifdef SK_DEBUG
358 void GrBatchAtlas::uploadPlotsToTexture(GrTextureUploader uploader) {
359 GrBatchPlotList::Iter plotIter;
360 plotIter.init(fPlotList, GrBatchPlotList::Iter::kHead_IterStart);
361 GrBatchPlot* plot;
362 while ((plot = plotIter.get())) {
363 plot->uploadToTexture(uploader);
364 plotIter.next();
365 }
366 }
367 #endif
OLDNEW
« no previous file with comments | « src/gpu/GrBatchAtlas.h ('k') | src/gpu/GrBatchTarget.h » ('j') | src/gpu/GrBatchTarget.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698