1 /* 2 * Copyright 2014 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 "GrAtlas.h" 9 #include "GrGpu.h" 10 #include "GrLayerCache.h" 11 12 DECLARE_SKMESSAGEBUS_MESSAGE(GrPictureDeletedMessage); 13 14 #ifdef SK_DEBUG 15 void GrCachedLayer::validate(const GrTexture* backingTexture) const { 16 SkASSERT(SK_InvalidGenID != fKey.pictureID()); 17 SkASSERT(fKey.start() > 0 && fKey.stop() > 0); 18 19 20 if (fTexture) { 21 // If the layer is in some texture then it must occupy some rectangle 22 SkASSERT(!fRect.isEmpty()); 23 if (!this->isAtlased()) { 24 // If it isn't atlased then the rectangle should start at the origin 25 SkASSERT(0.0f == fRect.fLeft && 0.0f == fRect.fTop); 26 } 27 } else { 28 SkASSERT(fRect.isEmpty()); 29 SkASSERT(NULL == fPlot); 30 SkASSERT(!fLocked); // layers without a texture cannot be locked 31 } 32 33 if (fPlot) { 34 // If a layer has a plot (i.e., is atlased) then it must point to 35 // the backing texture. Additionally, its rect should be non-empty. 36 SkASSERT(fTexture && backingTexture == fTexture); 37 SkASSERT(!fRect.isEmpty()); 38 } 39 40 if (fLocked) { 41 // If a layer is locked it must have a texture (though it need not be 42 // the atlas-backing texture) and occupy some space. 43 SkASSERT(fTexture); 44 SkASSERT(!fRect.isEmpty()); 45 } 46 } 47 48 class GrAutoValidateLayer : ::SkNoncopyable { 49 public: 50 GrAutoValidateLayer(GrTexture* backingTexture, const GrCachedLayer* layer) 51 : fBackingTexture(backingTexture) 52 , fLayer(layer) { 53 if (fLayer) { 54 fLayer->validate(backingTexture); 55 } 56 } 57 ~GrAutoValidateLayer() { 58 if (fLayer) { 59 fLayer->validate(fBackingTexture); 60 } 61 } 62 void setBackingTexture(GrTexture* backingTexture) { 63 SkASSERT(NULL == fBackingTexture || fBackingTexture == backingTexture); 64 fBackingTexture = backingTexture; 65 } 66 67 private: 68 const GrTexture* fBackingTexture; 69 const GrCachedLayer* fLayer; 70 }; 71 #endif 72 73 GrLayerCache::GrLayerCache(GrContext* context) 74 : fContext(context) { 75 this->initAtlas(); 76 memset(fPlotLocks, 0, sizeof(fPlotLocks)); 77 } 78 79 GrLayerCache::~GrLayerCache() { 80 81 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); 82 for (; !iter.done(); ++iter) { 83 GrCachedLayer* layer = &(*iter); 84 this->unlock(layer); 85 SkDELETE(layer); 86 } 87 88 // The atlas only lets go of its texture when the atlas is deleted. 89 fAtlas.free(); 90 } 91 92 void GrLayerCache::initAtlas() { 93 SkASSERT(NULL == fAtlas.get()); 94 95 SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight); 96 fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfig, 97 kRenderTarget_GrTextureFlagBit, 98 textureSize, kNumPlotsX, kNumPlotsY, false))); 99 } 100 101 void GrLayerCache::freeAll() { 102 103 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); 104 for (; !iter.done(); ++iter) { 105 GrCachedLayer* layer = &(*iter); 106 this->unlock(layer); 107 SkDELETE(layer); 108 } 109 fLayerHash.rewind(); 110 111 // The atlas only lets go of its texture when the atlas is deleted. 112 fAtlas.free(); 113 // GrLayerCache always assumes an atlas exists so recreate it. The atlas 114 // lazily allocates a replacement texture so reallocating a new 115 // atlas here won't disrupt a GrContext::abandonContext or freeGpuResources. 116 // TODO: Make GrLayerCache lazily allocate the atlas manager? 117 this->initAtlas(); 118 } 119 120 GrCachedLayer* GrLayerCache::createLayer(uint32_t pictureID, 121 int start, int stop, 122 const SkIPoint& offset, 123 const SkMatrix& ctm, 124 const SkPaint* paint) { 125 SkASSERT(pictureID != SK_InvalidGenID && start > 0 && stop > 0); 126 127 GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (pictureID, start, stop, offset, ctm, paint)); 128 fLayerHash.add(layer); 129 return layer; 130 } 131 132 GrCachedLayer* GrLayerCache::findLayer(uint32_t pictureID, 133 int start, int stop, 134 const SkIPoint& offset, 135 const SkMatrix& ctm) { 136 SkASSERT(pictureID != SK_InvalidGenID && start > 0 && stop > 0); 137 return fLayerHash.find(GrCachedLayer::Key(pictureID, start, stop, offset, ctm)); 138 } 139 140 GrCachedLayer* GrLayerCache::findLayerOrCreate(uint32_t pictureID, 141 int start, int stop, 142 const SkIPoint& offset, 143 const SkMatrix& ctm, 144 const SkPaint* paint) { 145 SkASSERT(pictureID != SK_InvalidGenID && start > 0 && stop > 0); 146 GrCachedLayer* layer = fLayerHash.find(GrCachedLayer::Key(pictureID, start, stop, offset, ctm)); 147 if (NULL == layer) { 148 layer = this->createLayer(pictureID, start, stop, offset, ctm, paint); 149 } 150 151 return layer; 152 } 153 154 bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc, bool dontAtlas) { 155 SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);) 156 157 if (layer->locked()) { 158 // This layer is already locked 159 #ifdef SK_DEBUG 160 if (layer->isAtlased()) { 161 // It claims to be atlased 162 SkASSERT(!dontAtlas); 163 SkASSERT(layer->rect().width() == desc.fWidth); 164 SkASSERT(layer->rect().height() == desc.fHeight); 165 } 166 #endif 167 return false; 168 } 169 170 if (layer->isAtlased()) { 171 // Hooray it is still in the atlas - make sure it stays there 172 SkASSERT(!dontAtlas); 173 layer->setLocked(true); 174 fPlotLocks[layer->plot()->id()]++; 175 return false; 176 } else if (!dontAtlas && PlausiblyAtlasable(desc.fWidth, desc.fHeight)) { 177 // Not in the atlas - will it fit? 178 GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID()); 179 if (NULL == pictInfo) { 180 pictInfo = SkNEW_ARGS(GrPictureInfo, (layer->pictureID())); 181 fPictureHash.add(pictInfo); 182 } 183 184 SkIPoint16 loc; 185 for (int i = 0; i < 2; ++i) { // extra pass in case we fail to add but are able to purge 186 GrPlot* plot = fAtlas->addToAtlas(&pictInfo->fPlotUsage, 187 desc.fWidth, desc.fHeight, 188 NULL, &loc); 189 // addToAtlas can allocate the backing texture 190 SkDEBUGCODE(avl.setBackingTexture(fAtlas->getTexture())); 191 if (plot) { 192 // The layer was successfully added to the atlas 193 GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY, 194 SkToS16(desc.fWidth), 195 SkToS16(desc.fHeight)); 196 layer->setTexture(fAtlas->getTexture(), bounds); 197 layer->setPlot(plot); 198 layer->setLocked(true); 199 fPlotLocks[layer->plot()->id()]++; 200 return true; 201 } 202 203 // The layer was rejected by the atlas (even though we know it is 204 // plausibly atlas-able). See if a plot can be purged and try again. 205 if (!this->purgePlot()) { 206 break; // We weren't able to purge any plots 207 } 208 } 209 } 210 211 // The texture wouldn't fit in the cache - give it it's own texture. 212 // This path always uses a new scratch texture and (thus) doesn't cache anything. 213 // This can yield a lot of re-rendering 214 SkAutoTUnref<GrTexture> tex(fContext->lockAndRefScratchTexture(desc, 215 GrContext::kApprox_ScratchTexMatch)); 216 217 layer->setTexture(tex, GrIRect16::MakeWH(SkToS16(desc.fWidth), SkToS16(desc.fHeight))); 218 layer->setLocked(true); 219 return true; 220 } 221 222 void GrLayerCache::unlock(GrCachedLayer* layer) { 223 SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);) 224 225 if (NULL == layer || !layer->locked()) { 226 // invalid or not locked 227 return; 228 } 229 230 if (layer->isAtlased()) { 231 const int plotID = layer->plot()->id(); 232 233 SkASSERT(fPlotLocks[plotID] > 0); 234 fPlotLocks[plotID]--; 235 // At this point we could aggressively clear out un-locked plots but 236 // by delaying we may be able to reuse some of the atlased layers later. 237 #if DISABLE_CACHING 238 // This testing code aggressively removes the atlased layers. This 239 // can be used to separate the performance contribution of less 240 // render target pingponging from that due to the re-use of cached layers 241 GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID()); 242 SkASSERT(pictInfo); 243 244 GrAtlas::RemovePlot(&pictInfo->fPlotUsage, layer->plot()); 245 246 layer->setPlot(NULL); 247 layer->setTexture(NULL, GrIRect16::MakeEmpty()); 248 #endif 249 250 } else { 251 fContext->unlockScratchTexture(layer->texture()); 252 layer->setTexture(NULL, GrIRect16::MakeEmpty()); 253 } 254 255 layer->setLocked(false); 256 } 257 258 #ifdef SK_DEBUG 259 void GrLayerCache::validate() const { 260 int plotLocks[kNumPlotsX * kNumPlotsY]; 261 memset(plotLocks, 0, sizeof(plotLocks)); 262 263 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::ConstIter iter(&fLayerHash); 264 for (; !iter.done(); ++iter) { 265 const GrCachedLayer* layer = &(*iter); 266 267 layer->validate(fAtlas->getTexture()); 268 269 const GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID()); 270 if (pictInfo) { 271 // In aggressive cleanup mode a picture info should only exist if 272 // it has some atlased layers 273 #if !DISABLE_CACHING 274 SkASSERT(!pictInfo->fPlotUsage.isEmpty()); 275 #endif 276 } else { 277 // If there is no picture info for this layer then all of its 278 // layers should be non-atlased. 279 SkASSERT(!layer->isAtlased()); 280 } 281 282 if (layer->plot()) { 283 SkASSERT(pictInfo); 284 SkASSERT(pictInfo->fPictureID == layer->pictureID()); 285 286 SkASSERT(pictInfo->fPlotUsage.contains(layer->plot())); 287 288 if (layer->locked()) { 289 plotLocks[layer->plot()->id()]++; 290 } 291 } 292 } 293 294 for (int i = 0; i < kNumPlotsX*kNumPlotsY; ++i) { 295 SkASSERT(plotLocks[i] == fPlotLocks[i]); 296 } 297 } 298 299 class GrAutoValidateCache : ::SkNoncopyable { 300 public: 301 explicit GrAutoValidateCache(GrLayerCache* cache) 302 : fCache(cache) { 303 fCache->validate(); 304 } 305 ~GrAutoValidateCache() { 306 fCache->validate(); 307 } 308 private: 309 GrLayerCache* fCache; 310 }; 311 #endif 312 313 void GrLayerCache::purge(uint32_t pictureID) { 314 315 SkDEBUGCODE(GrAutoValidateCache avc(this);) 316 317 // We need to find all the layers associated with 'picture' and remove them. 318 SkTDArray<GrCachedLayer*> toBeRemoved; 319 320 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); 321 for (; !iter.done(); ++iter) { 322 if (pictureID == (*iter).pictureID()) { 323 *toBeRemoved.append() = &(*iter); 324 } 325 } 326 327 for (int i = 0; i < toBeRemoved.count(); ++i) { 328 this->unlock(toBeRemoved[i]); 329 fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i])); 330 SkDELETE(toBeRemoved[i]); 331 } 332 333 GrPictureInfo* pictInfo = fPictureHash.find(pictureID); 334 if (pictInfo) { 335 fPictureHash.remove(pictureID); 336 SkDELETE(pictInfo); 337 } 338 } 339 340 bool GrLayerCache::purgePlot() { 341 SkDEBUGCODE(GrAutoValidateCache avc(this);) 342 343 GrAtlas::PlotIter iter; 344 GrPlot* plot; 345 for (plot = fAtlas->iterInit(&iter, GrAtlas::kLRUFirst_IterOrder); 346 plot; 347 plot = iter.prev()) { 348 if (fPlotLocks[plot->id()] > 0) { 349 continue; 350 } 351 352 this->purgePlot(plot); 353 return true; 354 } 355 356 return false; 357 } 358 359 void GrLayerCache::purgePlot(GrPlot* plot) { 360 SkASSERT(0 == fPlotLocks[plot->id()]); 361 362 // We need to find all the layers in 'plot' and remove them. 363 SkTDArray<GrCachedLayer*> toBeRemoved; 364 365 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); 366 for (; !iter.done(); ++iter) { 367 if (plot == (*iter).plot()) { 368 *toBeRemoved.append() = &(*iter); 369 } 370 } 371 372 for (int i = 0; i < toBeRemoved.count(); ++i) { 373 SkASSERT(!toBeRemoved[i]->locked()); 374 375 GrPictureInfo* pictInfo = fPictureHash.find(toBeRemoved[i]->pictureID()); 376 SkASSERT(pictInfo); 377 378 GrAtlas::RemovePlot(&pictInfo->fPlotUsage, plot); 379 380 // Aggressively remove layers and, if now totally uncached, picture info 381 fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i])); 382 SkDELETE(toBeRemoved[i]); 383 384 if (pictInfo->fPlotUsage.isEmpty()) { 385 fPictureHash.remove(pictInfo->fPictureID); 386 SkDELETE(pictInfo); 387 } 388 } 389 390 plot->resetRects(); 391 } 392 393 void GrLayerCache::purgeAll() { 394 GrAtlas::PlotIter iter; 395 GrPlot* plot; 396 for (plot = fAtlas->iterInit(&iter, GrAtlas::kLRUFirst_IterOrder); 397 plot; 398 plot = iter.prev()) { 399 SkASSERT(0 == fPlotLocks[plot->id()]); 400 401 this->purgePlot(plot); 402 } 403 } 404 405 class GrPictureDeletionListener : public SkPicture::DeletionListener { 406 virtual void onDeletion(uint32_t pictureID) SK_OVERRIDE{ 407 const GrPictureDeletedMessage message = { pictureID }; 408 SkMessageBus<GrPictureDeletedMessage>::Post(message); 409 } 410 }; 411 412 void GrLayerCache::trackPicture(const SkPicture* picture) { 413 if (NULL == fDeletionListener) { 414 fDeletionListener.reset(SkNEW(GrPictureDeletionListener)); 415 } 416 417 picture->addDeletionListener(fDeletionListener); 418 } 419 420 void GrLayerCache::processDeletedPictures() { 421 SkTDArray<GrPictureDeletedMessage> deletedPictures; 422 fPictDeletionInbox.poll(&deletedPictures); 423 424 for (int i = 0; i < deletedPictures.count(); i++) { 425 this->purge(deletedPictures[i].pictureID); 426 } 427 } 428 429