LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/effects - GrTextureStripAtlas.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 199 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 18 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012 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 "GrTextureStripAtlas.h"
       9             : #include "GrContext.h"
      10             : #include "GrContextPriv.h"
      11             : #include "GrResourceProvider.h"
      12             : #include "GrSurfaceContext.h"
      13             : #include "SkGr.h"
      14             : #include "SkPixelRef.h"
      15             : #include "SkTSearch.h"
      16             : 
      17             : #ifdef SK_DEBUG
      18             :     #define VALIDATE this->validate()
      19             : #else
      20             :     #define VALIDATE
      21             : #endif
      22             : 
      23           0 : class GrTextureStripAtlas::Hash : public SkTDynamicHash<GrTextureStripAtlas::AtlasEntry,
      24             :                                                         GrTextureStripAtlas::Desc> {};
      25             : 
      26             : int32_t GrTextureStripAtlas::gCacheCount = 0;
      27             : 
      28             : GrTextureStripAtlas::Hash* GrTextureStripAtlas::gAtlasCache = nullptr;
      29             : 
      30           0 : GrTextureStripAtlas::Hash* GrTextureStripAtlas::GetCache() {
      31             : 
      32           0 :     if (nullptr == gAtlasCache) {
      33           0 :         gAtlasCache = new Hash;
      34             :     }
      35             : 
      36           0 :     return gAtlasCache;
      37             : }
      38             : 
      39             : // Remove the specified atlas from the cache
      40           0 : void GrTextureStripAtlas::CleanUp(const GrContext*, void* info) {
      41           0 :     SkASSERT(info);
      42             : 
      43           0 :     AtlasEntry* entry = static_cast<AtlasEntry*>(info);
      44             : 
      45             :     // remove the cache entry
      46           0 :     GetCache()->remove(entry->fDesc);
      47             : 
      48             :     // remove the actual entry
      49           0 :     delete entry;
      50             : 
      51           0 :     if (0 == GetCache()->count()) {
      52           0 :         delete gAtlasCache;
      53           0 :         gAtlasCache = nullptr;
      54             :     }
      55           0 : }
      56             : 
      57           0 : GrTextureStripAtlas* GrTextureStripAtlas::GetAtlas(const GrTextureStripAtlas::Desc& desc) {
      58           0 :     AtlasEntry* entry = GetCache()->find(desc);
      59           0 :     if (nullptr == entry) {
      60           0 :         entry = new AtlasEntry;
      61             : 
      62           0 :         entry->fAtlas = new GrTextureStripAtlas(desc);
      63           0 :         entry->fDesc = desc;
      64             : 
      65           0 :         desc.fContext->addCleanUp(CleanUp, entry);
      66             : 
      67           0 :         GetCache()->add(entry);
      68             :     }
      69             : 
      70           0 :     return entry->fAtlas;
      71             : }
      72             : 
      73           0 : GrTextureStripAtlas::GrTextureStripAtlas(GrTextureStripAtlas::Desc desc)
      74           0 :     : fCacheKey(sk_atomic_inc(&gCacheCount))
      75             :     , fLockedRows(0)
      76             :     , fDesc(desc)
      77           0 :     , fNumRows(desc.fHeight / desc.fRowHeight)
      78           0 :     , fRows(new AtlasRow[fNumRows])
      79             :     , fLRUFront(nullptr)
      80           0 :     , fLRUBack(nullptr) {
      81           0 :     SkASSERT(fNumRows * fDesc.fRowHeight == fDesc.fHeight);
      82           0 :     this->initLRU();
      83           0 :     fNormalizedYHeight = SK_Scalar1 / fDesc.fHeight;
      84           0 :     VALIDATE;
      85           0 : }
      86             : 
      87           0 : GrTextureStripAtlas::~GrTextureStripAtlas() { delete[] fRows; }
      88             : 
      89           0 : int GrTextureStripAtlas::lockRow(const SkBitmap& bitmap) {
      90           0 :     VALIDATE;
      91           0 :     if (0 == fLockedRows) {
      92           0 :         this->lockTexture();
      93           0 :         if (!fTexContext) {
      94           0 :             return -1;
      95             :         }
      96             :     }
      97             : 
      98           0 :     int key = bitmap.getGenerationID();
      99           0 :     int rowNumber = -1;
     100           0 :     int index = this->searchByKey(key);
     101             : 
     102           0 :     if (index >= 0) {
     103             :         // We already have the data in a row, so we can just return that row
     104           0 :         AtlasRow* row = fKeyTable[index];
     105           0 :         if (0 == row->fLocks) {
     106           0 :             this->removeFromLRU(row);
     107             :         }
     108           0 :         ++row->fLocks;
     109           0 :         ++fLockedRows;
     110             : 
     111             :         // Since all the rows are always stored in a contiguous array, we can save the memory
     112             :         // required for storing row numbers and just compute it with some pointer arithmetic
     113           0 :         rowNumber = static_cast<int>(row - fRows);
     114             :     } else {
     115             :         // ~index is the index where we will insert the new key to keep things sorted
     116           0 :         index = ~index;
     117             : 
     118             :         // We don't have this data cached, so pick the least recently used row to copy into
     119           0 :         AtlasRow* row = this->getLRU();
     120             : 
     121           0 :         ++fLockedRows;
     122             : 
     123           0 :         if (nullptr == row) {
     124             :             // force a flush, which should unlock all the rows; then try again
     125           0 :             fDesc.fContext->contextPriv().flush(nullptr); // tighten this up?
     126           0 :             row = this->getLRU();
     127           0 :             if (nullptr == row) {
     128           0 :                 --fLockedRows;
     129           0 :                 return -1;
     130             :             }
     131             :         }
     132             : 
     133           0 :         this->removeFromLRU(row);
     134             : 
     135           0 :         uint32_t oldKey = row->fKey;
     136             : 
     137             :         // If we are writing into a row that already held bitmap data, we need to remove the
     138             :         // reference to that genID which is stored in our sorted table of key values.
     139           0 :         if (oldKey != kEmptyAtlasRowKey) {
     140             : 
     141             :             // Find the entry in the list; if it's before the index where we plan on adding the new
     142             :             // entry, we decrement since it will shift elements ahead of it back by one.
     143           0 :             int oldIndex = this->searchByKey(oldKey);
     144           0 :             if (oldIndex < index) {
     145           0 :                 --index;
     146             :             }
     147             : 
     148           0 :             fKeyTable.remove(oldIndex);
     149             :         }
     150             : 
     151           0 :         row->fKey = key;
     152           0 :         row->fLocks = 1;
     153           0 :         fKeyTable.insert(index, 1, &row);
     154           0 :         rowNumber = static_cast<int>(row - fRows);
     155             : 
     156           0 :         SkAutoLockPixels lock(bitmap);
     157             : 
     158           0 :         SkASSERT(bitmap.width() == fDesc.fWidth);
     159           0 :         SkASSERT(bitmap.height() == fDesc.fRowHeight);
     160             : 
     161             :         // Pass in the kDontFlush flag, since we know we're writing to a part of this texture
     162             :         // that is not currently in use
     163           0 :         fTexContext->writePixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(),
     164           0 :                                  0, rowNumber * fDesc.fRowHeight,
     165           0 :                                  GrContextPriv::kDontFlush_PixelOpsFlag);
     166             :     }
     167             : 
     168           0 :     SkASSERT(rowNumber >= 0);
     169           0 :     VALIDATE;
     170           0 :     return rowNumber;
     171             : }
     172             : 
     173           0 : sk_sp<GrTextureProxy> GrTextureStripAtlas::asTextureProxyRef() const {
     174           0 :     return fTexContext->asTextureProxyRef();
     175             : }
     176             : 
     177           0 : void GrTextureStripAtlas::unlockRow(int row) {
     178           0 :     VALIDATE;
     179           0 :     --fRows[row].fLocks;
     180           0 :     --fLockedRows;
     181           0 :     SkASSERT(fRows[row].fLocks >= 0 && fLockedRows >= 0);
     182           0 :     if (0 == fRows[row].fLocks) {
     183           0 :         this->appendLRU(fRows + row);
     184             :     }
     185           0 :     if (0 == fLockedRows) {
     186           0 :         this->unlockTexture();
     187             :     }
     188           0 :     VALIDATE;
     189           0 : }
     190             : 
     191           0 : GrTextureStripAtlas::AtlasRow* GrTextureStripAtlas::getLRU() {
     192             :     // Front is least-recently-used
     193           0 :     AtlasRow* row = fLRUFront;
     194           0 :     return row;
     195             : }
     196             : 
     197           0 : void GrTextureStripAtlas::lockTexture() {
     198           0 :     GrSurfaceDesc texDesc;
     199           0 :     texDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
     200           0 :     texDesc.fWidth = fDesc.fWidth;
     201           0 :     texDesc.fHeight = fDesc.fHeight;
     202           0 :     texDesc.fConfig = fDesc.fConfig;
     203             : 
     204           0 :     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
     205           0 :     GrUniqueKey key;
     206           0 :     GrUniqueKey::Builder builder(&key, kDomain, 1);
     207           0 :     builder[0] = static_cast<uint32_t>(fCacheKey);
     208           0 :     builder.finish();
     209             : 
     210           0 :     sk_sp<GrTextureProxy> proxy = fDesc.fContext->resourceProvider()->findProxyByUniqueKey(key);
     211           0 :     if (!proxy) {
     212           0 :         proxy = GrSurfaceProxy::MakeDeferred(fDesc.fContext->resourceProvider(),
     213             :                                              texDesc, SkBackingFit::kExact,
     214             :                                              SkBudgeted::kYes,
     215           0 :                                              GrResourceProvider::kNoPendingIO_Flag);
     216           0 :         if (!proxy) {
     217           0 :             return;
     218             :         }
     219             : 
     220           0 :         fDesc.fContext->resourceProvider()->assignUniqueKeyToProxy(key, proxy.get());
     221             :         // This is a new texture, so all of our cache info is now invalid
     222           0 :         this->initLRU();
     223           0 :         fKeyTable.rewind();
     224             :     }
     225           0 :     SkASSERT(proxy);
     226           0 :     fTexContext = fDesc.fContext->contextPriv().makeWrappedSurfaceContext(std::move(proxy),
     227           0 :                                                                           nullptr);
     228             : }
     229             : 
     230           0 : void GrTextureStripAtlas::unlockTexture() {
     231           0 :     SkASSERT(fTexContext && 0 == fLockedRows);
     232           0 :     fTexContext.reset();
     233           0 : }
     234             : 
     235           0 : void GrTextureStripAtlas::initLRU() {
     236           0 :     fLRUFront = nullptr;
     237           0 :     fLRUBack = nullptr;
     238             :     // Initially all the rows are in the LRU list
     239           0 :     for (int i = 0; i < fNumRows; ++i) {
     240           0 :         fRows[i].fKey = kEmptyAtlasRowKey;
     241           0 :         fRows[i].fNext = nullptr;
     242           0 :         fRows[i].fPrev = nullptr;
     243           0 :         this->appendLRU(fRows + i);
     244             :     }
     245           0 :     SkASSERT(nullptr == fLRUFront || nullptr == fLRUFront->fPrev);
     246           0 :     SkASSERT(nullptr == fLRUBack || nullptr == fLRUBack->fNext);
     247           0 : }
     248             : 
     249           0 : void GrTextureStripAtlas::appendLRU(AtlasRow* row) {
     250           0 :     SkASSERT(nullptr == row->fPrev && nullptr == row->fNext);
     251           0 :     if (nullptr == fLRUFront && nullptr == fLRUBack) {
     252           0 :         fLRUFront = row;
     253           0 :         fLRUBack = row;
     254             :     } else {
     255           0 :         row->fPrev = fLRUBack;
     256           0 :         fLRUBack->fNext = row;
     257           0 :         fLRUBack = row;
     258             :     }
     259           0 : }
     260             : 
     261           0 : void GrTextureStripAtlas::removeFromLRU(AtlasRow* row) {
     262           0 :     SkASSERT(row);
     263           0 :     if (row->fNext && row->fPrev) {
     264           0 :         row->fPrev->fNext = row->fNext;
     265           0 :         row->fNext->fPrev = row->fPrev;
     266             :     } else {
     267           0 :         if (nullptr == row->fNext) {
     268           0 :             SkASSERT(row == fLRUBack);
     269           0 :             fLRUBack = row->fPrev;
     270           0 :             if (fLRUBack) {
     271           0 :                 fLRUBack->fNext = nullptr;
     272             :             }
     273             :         }
     274           0 :         if (nullptr == row->fPrev) {
     275           0 :             SkASSERT(row == fLRUFront);
     276           0 :             fLRUFront = row->fNext;
     277           0 :             if (fLRUFront) {
     278           0 :                 fLRUFront->fPrev = nullptr;
     279             :             }
     280             :         }
     281             :     }
     282           0 :     row->fNext = nullptr;
     283           0 :     row->fPrev = nullptr;
     284           0 : }
     285             : 
     286           0 : int GrTextureStripAtlas::searchByKey(uint32_t key) {
     287           0 :     AtlasRow target;
     288           0 :     target.fKey = key;
     289             :     return SkTSearch<const AtlasRow,
     290           0 :                      GrTextureStripAtlas::KeyLess>((const AtlasRow**)fKeyTable.begin(),
     291             :                                                    fKeyTable.count(),
     292             :                                                    &target,
     293           0 :                                                    sizeof(AtlasRow*));
     294             : }
     295             : 
     296             : #ifdef SK_DEBUG
     297           0 : void GrTextureStripAtlas::validate() {
     298             : 
     299             :     // Our key table should be sorted
     300           0 :     uint32_t prev = 1 > fKeyTable.count() ? 0 : fKeyTable[0]->fKey;
     301           0 :     for (int i = 1; i < fKeyTable.count(); ++i) {
     302           0 :         SkASSERT(prev < fKeyTable[i]->fKey);
     303           0 :         SkASSERT(fKeyTable[i]->fKey != kEmptyAtlasRowKey);
     304           0 :         prev = fKeyTable[i]->fKey;
     305             :     }
     306             : 
     307           0 :     int lruCount = 0;
     308             :     // Validate LRU pointers, and count LRU entries
     309           0 :     SkASSERT(nullptr == fLRUFront || nullptr == fLRUFront->fPrev);
     310           0 :     SkASSERT(nullptr == fLRUBack  || nullptr == fLRUBack->fNext);
     311           0 :     for (AtlasRow* r = fLRUFront; r != nullptr; r = r->fNext) {
     312           0 :         if (nullptr == r->fNext) {
     313           0 :             SkASSERT(r == fLRUBack);
     314             :         } else {
     315           0 :             SkASSERT(r->fNext->fPrev == r);
     316             :         }
     317           0 :         ++lruCount;
     318             :     }
     319             : 
     320           0 :     int rowLocks = 0;
     321           0 :     int freeRows = 0;
     322             : 
     323           0 :     for (int i = 0; i < fNumRows; ++i) {
     324           0 :         rowLocks += fRows[i].fLocks;
     325           0 :         if (0 == fRows[i].fLocks) {
     326           0 :             ++freeRows;
     327           0 :             bool inLRU = false;
     328             :             // Step through the LRU and make sure it's present
     329           0 :             for (AtlasRow* r = fLRUFront; r != nullptr; r = r->fNext) {
     330           0 :                 if (r == &fRows[i]) {
     331           0 :                     inLRU = true;
     332           0 :                     break;
     333             :                 }
     334             :             }
     335           0 :             SkASSERT(inLRU);
     336             :         } else {
     337             :             // If we are locked, we should have a key
     338           0 :             SkASSERT(kEmptyAtlasRowKey != fRows[i].fKey);
     339             :         }
     340             : 
     341             :         // If we have a key != kEmptyAtlasRowKey, it should be in the key table
     342           0 :         SkASSERT(fRows[i].fKey == kEmptyAtlasRowKey || this->searchByKey(fRows[i].fKey) >= 0);
     343             :     }
     344             : 
     345             :     // Our count of locks should equal the sum of row locks, unless we ran out of rows and flushed,
     346             :     // in which case we'll have one more lock than recorded in the rows (to represent the pending
     347             :     // lock of a row; which ensures we don't unlock the texture prematurely).
     348           0 :     SkASSERT(rowLocks == fLockedRows || rowLocks + 1 == fLockedRows);
     349             : 
     350             :     // We should have one lru entry for each free row
     351           0 :     SkASSERT(freeRows == lruCount);
     352             : 
     353             :     // If we have locked rows, we should have a locked texture, otherwise
     354             :     // it should be unlocked
     355           0 :     if (fLockedRows == 0) {
     356           0 :         SkASSERT(!fTexContext);
     357             :     } else {
     358           0 :         SkASSERT(fTexContext);
     359             :     }
     360           0 : }
     361             : #endif

Generated by: LCOV version 1.13