Chromium Code Reviews| 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 |