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 "GrLayerAtlas.h" 9 #include "GrContext.h" 10 #include "GrDrawContext.h" 11 #include "GrGpu.h" 12 #include "GrLayerCache.h" 13 #include "GrSurfacePriv.h" 14 15 #ifdef SK_DEBUG 16 void GrCachedLayer::validate(const GrTexture* backingTexture) const { 17 SkASSERT(SK_InvalidGenID != fKey.pictureID()); 18 19 if (fTexture) { 20 // If the layer is in some texture then it must occupy some rectangle 21 SkASSERT(!fRect.isEmpty()); 22 if (!this->isAtlased()) { 23 // If it isn't atlased then the rectangle should start at the origin 24 SkASSERT(0.0f == fRect.fLeft && 0.0f == fRect.fTop); 25 } 26 } else { 27 SkASSERT(fRect.isEmpty()); 28 SkASSERT(nullptr == fPlot); 29 SkASSERT(!fLocked); // layers without a texture cannot be locked 30 SkASSERT(!fAtlased); // can't be atlased if it doesn't have a texture 31 } 32 33 if (fPlot) { 34 SkASSERT(fAtlased); 35 // If a layer has a plot (i.e., is atlased) then it must point to 36 // the backing texture. Additionally, its rect should be non-empty. 37 SkASSERT(fTexture && backingTexture == fTexture); 38 SkASSERT(!fRect.isEmpty()); 39 } 40 41 if (fLocked) { 42 // If a layer is locked it must have a texture (though it need not be 43 // the atlas-backing texture) and occupy some space. 44 SkASSERT(fTexture); 45 SkASSERT(!fRect.isEmpty()); 46 } 47 48 // Unfortunately there is a brief time where a layer can be locked 49 // but not used, so we can only check the "used implies locked" 50 // invariant. 51 if (fUses > 0) { 52 SkASSERT(fLocked); 53 } else { 54 SkASSERT(0 == fUses); 55 } 56 } 57 58 class GrAutoValidateLayer : ::SkNoncopyable { 59 public: 60 GrAutoValidateLayer(GrTexture* backingTexture, const GrCachedLayer* layer) 61 : fBackingTexture(backingTexture) 62 , fLayer(layer) { 63 if (fLayer) { 64 fLayer->validate(backingTexture); 65 } 66 } 67 ~GrAutoValidateLayer() { 68 if (fLayer) { 69 fLayer->validate(fBackingTexture); 70 } 71 } 72 void setBackingTexture(GrTexture* backingTexture) { 73 SkASSERT(nullptr == fBackingTexture || fBackingTexture == backingTexture); 74 fBackingTexture = backingTexture; 75 } 76 77 private: 78 const GrTexture* fBackingTexture; 79 const GrCachedLayer* fLayer; 80 }; 81 #endif 82 83 GrLayerCache::GrLayerCache(GrContext* context) 84 : fContext(context) { 85 memset(fPlotLocks, 0, sizeof(fPlotLocks)); 86 } 87 88 GrLayerCache::~GrLayerCache() { 89 90 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); 91 for (; !iter.done(); ++iter) { 92 GrCachedLayer* layer = &(*iter); 93 SkASSERT(0 == layer->uses()); 94 this->unlock(layer); 95 delete layer; 96 } 97 98 SkASSERT(0 == fPictureHash.count()); 99 100 // The atlas only lets go of its texture when the atlas is deleted. 101 fAtlas.free(); 102 } 103 104 void GrLayerCache::initAtlas() { 105 SkASSERT(nullptr == fAtlas.get()); 106 GR_STATIC_ASSERT(kNumPlotsX*kNumPlotsX == GrPictureInfo::kNumPlots); 107 108 SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight); 109 fAtlas.reset(new GrLayerAtlas(fContext->textureProvider(), kSkia8888_GrPixelConfig, 110 kRenderTarget_GrSurfaceFlag, textureSize, 111 kNumPlotsX, kNumPlotsY)); 112 } 113 114 void GrLayerCache::freeAll() { 115 116 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); 117 for (; !iter.done(); ++iter) { 118 GrCachedLayer* layer = &(*iter); 119 this->unlock(layer); 120 delete layer; 121 } 122 fLayerHash.rewind(); 123 124 if (fAtlas) { 125 fAtlas->resetPlots(); 126 fAtlas->detachBackingTexture(); 127 } 128 } 129 130 GrCachedLayer* GrLayerCache::createLayer(uint32_t pictureID, 131 int start, int stop, 132 const SkIRect& srcIR, 133 const SkIRect& dstIR, 134 const SkMatrix& initialMat, 135 const int* key, 136 int keySize, 137 const SkPaint* paint) { 138 SkASSERT(pictureID != SK_InvalidGenID && start >= 0 && stop > 0); 139 140 GrCachedLayer* layer = new GrCachedLayer(pictureID, start, stop, srcIR, dstIR, initialMat, key, 141 keySize, paint); 142 fLayerHash.add(layer); 143 return layer; 144 } 145 146 GrCachedLayer* GrLayerCache::findLayer(uint32_t pictureID, const SkMatrix& initialMat, 147 const int* key, int keySize) { 148 SkASSERT(pictureID != SK_InvalidGenID); 149 return fLayerHash.find(GrCachedLayer::Key(pictureID, initialMat, key, keySize)); 150 } 151 152 GrCachedLayer* GrLayerCache::findLayerOrCreate(uint32_t pictureID, 153 int start, int stop, 154 const SkIRect& srcIR, 155 const SkIRect& dstIR, 156 const SkMatrix& initialMat, 157 const int* key, 158 int keySize, 159 const SkPaint* paint) { 160 SkASSERT(pictureID != SK_InvalidGenID && start >= 0 && stop > 0); 161 GrCachedLayer* layer = fLayerHash.find(GrCachedLayer::Key(pictureID, initialMat, key, keySize)); 162 if (nullptr == layer) { 163 layer = this->createLayer(pictureID, start, stop, 164 srcIR, dstIR, initialMat, 165 key, keySize, paint); 166 } 167 168 return layer; 169 } 170 171 bool GrLayerCache::tryToAtlas(GrCachedLayer* layer, 172 const GrSurfaceDesc& desc, 173 bool* needsRendering) { 174 SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTextureOrNull() : nullptr, layer);) 175 176 SkASSERT(PlausiblyAtlasable(desc.fWidth, desc.fHeight)); 177 SkASSERT(0 == desc.fSampleCnt); 178 179 if (layer->locked()) { 180 // This layer is already locked 181 SkASSERT(fAtlas); 182 SkASSERT(layer->isAtlased()); 183 SkASSERT(layer->rect().width() == desc.fWidth); 184 SkASSERT(layer->rect().height() == desc.fHeight); 185 *needsRendering = false; 186 return true; 187 } 188 189 if (layer->isAtlased()) { 190 SkASSERT(fAtlas); 191 // Hooray it is still in the atlas - make sure it stays there 192 layer->setLocked(true); 193 this->incPlotLock(layer->plot()->id()); 194 *needsRendering = false; 195 return true; 196 } else { 197 if (!fAtlas) { 198 this->initAtlas(); 199 if (!fAtlas) { 200 return false; 201 } 202 } 203 // Not in the atlas - will it fit? 204 GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID()); 205 if (nullptr == pictInfo) { 206 pictInfo = new GrPictureInfo(layer->pictureID()); 207 fPictureHash.add(pictInfo); 208 } 209 210 SkIPoint16 loc; 211 for (int i = 0; i < 2; ++i) { // extra pass in case we fail to add but are able to purge 212 GrLayerAtlas::Plot* plot = fAtlas->addToAtlas(&pictInfo->fPlotUsage, 213 desc.fWidth, desc.fHeight, 214 &loc); 215 // addToAtlas can allocate the backing texture 216 SkDEBUGCODE(avl.setBackingTexture(fAtlas->getTexture())); 217 if (plot) { 218 #if !GR_CACHE_HOISTED_LAYERS 219 pictInfo->incPlotUsage(plot->id()); 220 #endif 221 // The layer was successfully added to the atlas 222 const SkIRect bounds = SkIRect::MakeXYWH(loc.fX, loc.fY, 223 desc.fWidth, desc.fHeight); 224 layer->setTexture(fAtlas->getTexture(), bounds, true); 225 layer->setPlot(plot); 226 layer->setLocked(true); 227 this->incPlotLock(layer->plot()->id()); 228 *needsRendering = true; 229 return true; 230 } 231 232 // The layer was rejected by the atlas (even though we know it is 233 // plausibly atlas-able). See if a plot can be purged and try again. 234 if (!this->purgePlots(true)) { 235 break; // We weren't able to purge any plots 236 } 237 } 238 239 if (pictInfo->fPlotUsage.isEmpty()) { 240 fPictureHash.remove(pictInfo->fPictureID); 241 delete pictInfo; 242 } 243 } 244 245 return false; 246 } 247 248 bool GrLayerCache::lock(GrCachedLayer* layer, const GrSurfaceDesc& desc, bool* needsRendering) { 249 if (layer->locked()) { 250 // This layer is already locked 251 *needsRendering = false; 252 return true; 253 } 254 255 // TODO: make the test for exact match depend on the image filters themselves 256 SkAutoTUnref<GrTexture> tex; 257 if (layer->fFilter) { 258 tex.reset(fContext->textureProvider()->createTexture(desc, SkBudgeted::kYes)); 259 } else { 260 tex.reset(fContext->textureProvider()->createApproxTexture(desc)); 261 } 262 263 if (!tex) { 264 return false; 265 } 266 267 layer->setTexture(tex, SkIRect::MakeWH(desc.fWidth, desc.fHeight), false); 268 layer->setLocked(true); 269 *needsRendering = true; 270 return true; 271 } 272 273 void GrLayerCache::unlock(GrCachedLayer* layer) { 274 SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTextureOrNull() : nullptr, layer);) 275 276 if (nullptr == layer || !layer->locked()) { 277 // invalid or not locked 278 return; 279 } 280 281 if (layer->isAtlased()) { 282 const int plotID = layer->plot()->id(); 283 284 this->decPlotLock(plotID); 285 // At this point we could aggressively clear out un-locked plots but 286 // by delaying we may be able to reuse some of the atlased layers later. 287 #if !GR_CACHE_HOISTED_LAYERS 288 // This testing code aggressively removes the atlased layers. This 289 // can be used to separate the performance contribution of less 290 // render target pingponging from that due to the re-use of cached layers 291 GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID()); 292 SkASSERT(pictInfo); 293 294 pictInfo->decPlotUsage(plotID); 295 296 if (0 == pictInfo->plotUsage(plotID)) { 297 pictInfo->fPlotUsage.removePlot(layer->plot()); 298 299 if (pictInfo->fPlotUsage.isEmpty()) { 300 fPictureHash.remove(pictInfo->fPictureID); 301 delete pictInfo; 302 } 303 } 304 305 layer->setPlot(nullptr); 306 layer->setTexture(nullptr, SkIRect::MakeEmpty(), false); 307 #endif 308 309 } else { 310 layer->setTexture(nullptr, SkIRect::MakeEmpty(), false); 311 } 312 313 layer->setLocked(false); 314 } 315 316 #ifdef SK_DEBUG 317 void GrLayerCache::validate() const { 318 int plotLocks[kNumPlotsX * kNumPlotsY]; 319 memset(plotLocks, 0, sizeof(plotLocks)); 320 321 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::ConstIter iter(&fLayerHash); 322 for (; !iter.done(); ++iter) { 323 const GrCachedLayer* layer = &(*iter); 324 325 layer->validate(fAtlas.get() ? fAtlas->getTextureOrNull() : nullptr); 326 327 const GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID()); 328 if (!pictInfo) { 329 // If there is no picture info for this picture then all of its 330 // layers should be non-atlased. 331 SkASSERT(!layer->isAtlased()); 332 } 333 334 if (layer->plot()) { 335 SkASSERT(pictInfo); 336 SkASSERT(pictInfo->fPictureID == layer->pictureID()); 337 338 SkASSERT(pictInfo->fPlotUsage.contains(layer->plot())); 339 #if !GR_CACHE_HOISTED_LAYERS 340 SkASSERT(pictInfo->plotUsage(layer->plot()->id()) > 0); 341 #endif 342 343 if (layer->locked()) { 344 plotLocks[layer->plot()->id()]++; 345 } 346 } 347 } 348 349 for (int i = 0; i < kNumPlotsX*kNumPlotsY; ++i) { 350 SkASSERT(plotLocks[i] == fPlotLocks[i]); 351 } 352 } 353 354 class GrAutoValidateCache : ::SkNoncopyable { 355 public: 356 explicit GrAutoValidateCache(GrLayerCache* cache) 357 : fCache(cache) { 358 fCache->validate(); 359 } 360 ~GrAutoValidateCache() { 361 fCache->validate(); 362 } 363 private: 364 GrLayerCache* fCache; 365 }; 366 #endif 367 368 void GrLayerCache::purge(uint32_t pictureID) { 369 370 SkDEBUGCODE(GrAutoValidateCache avc(this);) 371 372 // We need to find all the layers associated with 'picture' and remove them. 373 SkTDArray<GrCachedLayer*> toBeRemoved; 374 375 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); 376 for (; !iter.done(); ++iter) { 377 if (pictureID == (*iter).pictureID()) { 378 *toBeRemoved.append() = &(*iter); 379 } 380 } 381 382 for (int i = 0; i < toBeRemoved.count(); ++i) { 383 SkASSERT(0 == toBeRemoved[i]->uses()); 384 this->unlock(toBeRemoved[i]); 385 fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i])); 386 delete toBeRemoved[i]; 387 } 388 389 GrPictureInfo* pictInfo = fPictureHash.find(pictureID); 390 if (pictInfo) { 391 fPictureHash.remove(pictureID); 392 delete pictInfo; 393 } 394 } 395 396 bool GrLayerCache::purgePlots(bool justOne) { 397 SkDEBUGCODE(GrAutoValidateCache avc(this);) 398 SkASSERT(fAtlas); 399 400 bool anyPurged = false; 401 GrLayerAtlas::PlotIter iter; 402 GrLayerAtlas::Plot* plot; 403 for (plot = fAtlas->iterInit(&iter, GrLayerAtlas::kLRUFirst_IterOrder); 404 plot; 405 plot = iter.prev()) { 406 if (fPlotLocks[plot->id()] > 0) { 407 continue; 408 } 409 410 anyPurged = true; 411 this->purgePlot(plot); 412 if (justOne) { 413 break; 414 } 415 } 416 417 return anyPurged; 418 } 419 420 void GrLayerCache::purgePlot(GrLayerAtlas::Plot* plot) { 421 SkASSERT(0 == fPlotLocks[plot->id()]); 422 423 // We need to find all the layers in 'plot' and remove them. 424 SkTDArray<GrCachedLayer*> toBeRemoved; 425 426 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); 427 for (; !iter.done(); ++iter) { 428 if (plot == (*iter).plot()) { 429 *toBeRemoved.append() = &(*iter); 430 } 431 } 432 433 for (int i = 0; i < toBeRemoved.count(); ++i) { 434 SkASSERT(0 == toBeRemoved[i]->uses()); 435 SkASSERT(!toBeRemoved[i]->locked()); 436 437 uint32_t pictureIDToRemove = toBeRemoved[i]->pictureID(); 438 439 // Aggressively remove layers and, if it becomes totally uncached, delete the picture info 440 fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i])); 441 delete toBeRemoved[i]; 442 443 GrPictureInfo* pictInfo = fPictureHash.find(pictureIDToRemove); 444 if (pictInfo) { 445 #if !GR_CACHE_HOISTED_LAYERS 446 SkASSERT(0 == pictInfo->plotUsage(plot->id())); 447 #endif 448 pictInfo->fPlotUsage.removePlot(plot); 449 450 if (pictInfo->fPlotUsage.isEmpty()) { 451 fPictureHash.remove(pictInfo->fPictureID); 452 delete pictInfo; 453 } 454 } 455 } 456 457 plot->reset(); 458 } 459 460 #if !GR_CACHE_HOISTED_LAYERS 461 void GrLayerCache::purgeAll() { 462 if (!fAtlas) { 463 return; 464 } 465 466 this->purgePlots(false); // clear them all out 467 468 SkASSERT(0 == fPictureHash.count()); 469 470 if (fAtlas->getTextureOrNull()) { 471 SkAutoTUnref<GrDrawContext> drawContext( 472 fContext->drawContext(fAtlas->getTexture()->asRenderTarget())); 473 474 if (drawContext) { 475 drawContext->discard(); 476 } 477 } 478 } 479 #endif 480 481 void GrLayerCache::begin() { 482 if (!fAtlas) { 483 return; 484 } 485 486 if (!fAtlas->reattachBackingTexture()) { 487 // We weren't able to re-attach. Clear out all the atlased layers. 488 this->purgePlots(false); 489 SkASSERT(0 == fPictureHash.count()); 490 } 491 #ifdef SK_DEBUG 492 else { 493 // we've reattached - everything had better make sense 494 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); 495 for (; !iter.done(); ++iter) { 496 GrCachedLayer* layer = &(*iter); 497 498 if (layer->isAtlased()) { 499 SkASSERT(fAtlas->getTexture() == layer->texture()); 500 } 501 } 502 } 503 #endif 504 } 505 506 void GrLayerCache::end() { 507 if (!fAtlas) { 508 return; 509 } 510 511 // Adding this call will clear out all the layers in the atlas 512 //this->purgePlots(false); 513 514 fAtlas->detachBackingTexture(); 515 } 516 517 void GrLayerCache::processDeletedPictures() { 518 SkTArray<SkPicture::DeletionMessage> deletedPictures; 519 fPictDeletionInbox.poll(&deletedPictures); 520 521 for (int i = 0; i < deletedPictures.count(); i++) { 522 this->purge(deletedPictures[i].fUniqueID); 523 } 524 } 525 526 #ifdef SK_DEVELOPER 527 void GrLayerCache::writeLayersToDisk(const SkString& dirName) { 528 529 if (fAtlas) { 530 GrTexture* atlasTexture = fAtlas->getTextureOrNull(); 531 if (nullptr != atlasTexture) { 532 SkString fileName(dirName); 533 fileName.append("\\atlas.png"); 534 535 atlasTexture->surfacePriv().savePixels(fileName.c_str()); 536 } 537 } 538 539 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); 540 for (; !iter.done(); ++iter) { 541 GrCachedLayer* layer = &(*iter); 542 543 if (layer->isAtlased() || !layer->texture()) { 544 continue; 545 } 546 547 SkString fileName(dirName); 548 fileName.appendf("\\%d", layer->fKey.pictureID()); 549 for (int i = 0; i < layer->fKey.keySize(); ++i) { 550 fileName.appendf("-%d", layer->fKey.key()[i]); 551 } 552 fileName.appendf(".png"); 553 554 layer->texture()->surfacePriv().savePixels(fileName.c_str()); 555 } 556 } 557 #endif 558