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