@@ -82,6 +82,10 @@ PTEX_NAMESPACE_BEGIN
8282
8383void PtexCachedReader::release ()
8484{
85+ // Unref the texture, and log the texture as recently used if the ref count becomes 0. Note: If
86+ // the ref is negative after unref is called, it means the unref'd texture was not previously in
87+ // use which is an application error. In this case, the texture was presumably already logged as
88+ // recently used and we shouldn't log it again.
8589 if (0 == unref ()) {
8690 _cache->logRecentlyUsed (this );
8791 }
@@ -123,7 +127,6 @@ PtexTexture* PtexReaderCache::get(const char* filename, Ptex::String& error)
123127 // lookup reader in map
124128 StringKey key (filename);
125129 PtexCachedReader* reader = _files.get (key);
126- bool isNew = false ;
127130
128131 if (reader) {
129132 if (!reader->ok ()) return 0 ;
@@ -134,43 +137,36 @@ PtexTexture* PtexReaderCache::get(const char* filename, Ptex::String& error)
134137 reader->ref ();
135138 } else {
136139 reader = new PtexCachedReader (_premultiply, _io, _err, this );
137- isNew = true ;
140+ size_t newMemUsed = 0 ;
141+ PtexCachedReader* newreader = reader;
142+ reader = _files.tryInsert (key, reader, newMemUsed);
143+ adjustMemUsed (newMemUsed);
144+ if (reader != newreader) {
145+ // another thread got here first
146+ reader->ref ();
147+ delete newreader;
148+ }
138149 }
139150
140- bool needOpen = reader->needToOpen ();
141- if (needOpen) {
151+ if (reader->needToOpen ()) {
142152 std::string buffer;
143153 const char * pathToOpen = filename;
144154 // search for the file (unless we have an I/O handler)
145155 if (_io || findFile (pathToOpen, buffer, error)) {
146- reader->open (pathToOpen, error);
156+ if (reader->open (pathToOpen, error)) {
157+ reader->logOpen ();
158+ }
147159 } else {
148160 // flag reader as invalid so we don't try to open it again on next lookup
149161 reader->invalidate ();
150162 }
151163 }
152164
153- if (isNew) {
154- size_t newMemUsed = 0 ;
155- PtexCachedReader* newreader = reader;
156- reader = _files.tryInsert (key, reader, newMemUsed);
157- adjustMemUsed (newMemUsed);
158- if (reader != newreader) {
159- // another thread got here first
160- reader->ref ();
161- delete newreader;
162- }
163- }
164-
165165 if (!reader->ok ()) {
166166 reader->unref ();
167167 return 0 ;
168168 }
169169
170- if (needOpen) {
171- reader->logOpen ();
172- }
173-
174170 return reader;
175171}
176172
@@ -190,13 +186,14 @@ void PtexReaderCache::logRecentlyUsed(PtexCachedReader* reader)
190186 while (1 ) {
191187 MruList* mruList = _mruList;
192188 int slot = AtomicIncrement (&mruList->next )-1 ;
193- if (slot < numMruFiles ) {
189+ if (slot < maxMruFiles ) {
194190 mruList->files [slot] = reader;
191+ processMru ();
195192 return ;
196193 }
197194 // no mru slot available, process mru list and try again
198195 do processMru ();
199- while (_mruList->next >= numMruFiles );
196+ while (_mruList->next >= maxMruFiles );
200197 }
201198}
202199
@@ -205,7 +202,9 @@ void PtexReaderCache::processMru()
205202 // use a non-blocking lock so we can proceed as soon as space has been freed in the mru list
206203 // (which happens almost immediately in the processMru thread that has the lock)
207204 if (!_mruLock.trylock ()) return ;
208- if (_mruList->next < numMruFiles) {
205+
206+ if (!_mruList->next ) {
207+ // nothing to do
209208 _mruLock.unlock ();
210209 return ;
211210 }
@@ -217,7 +216,8 @@ void PtexReaderCache::processMru()
217216
218217 // extract relevant stats and add to open/active list
219218 size_t memUsedChange = 0 , filesOpenChange = 0 ;
220- for (int i = 0 ; i < numMruFiles; ++i) {
219+ int numFilesToProcess = std::min (int (mruList->next ), maxMruFiles);
220+ for (int i = 0 ; i < numFilesToProcess; ++i) {
221221 PtexCachedReader* reader;
222222 do { reader = mruList->files [i]; } while (!reader); // loop on (unlikely) race condition
223223 mruList->files [i] = 0 ;
@@ -237,50 +237,55 @@ void PtexReaderCache::processMru()
237237 AtomicStore (&mruList->next , 0 );
238238 adjustMemUsed (memUsedChange);
239239 adjustFilesOpen (filesOpenChange);
240+ _mruLock.unlock ();
240241
241- bool shouldPruneFiles = _filesOpen > _maxFiles;
242- bool shouldPruneData = _maxMem && _memUsed > _maxMem;
243-
244- if (shouldPruneFiles) {
245- pruneFiles ();
246- }
247- if (shouldPruneData) {
248- pruneData ();
242+ pruneFilesIfNeeded ();
243+ if (_maxMem) {
244+ pruneDataIfNeeded ();
249245 }
250- _mruLock.unlock ();
251246}
252247
253248
254- void PtexReaderCache::pruneFiles ()
249+ void PtexReaderCache::pruneFilesIfNeeded ()
255250{
256- size_t numToClose = _filesOpen - _maxFiles;
257- if (numToClose > 0 ) {
258- while (numToClose) {
259- PtexCachedReader* reader = _openFiles.pop ();
260- if (!reader) { _filesOpen = 0 ; break ; }
261- if (reader->tryClose ()) {
262- --numToClose;
263- --_filesOpen;
264- }
251+ while (_filesOpen > _maxFiles) {
252+ // close one file not currently in use, and then check again
253+ _mruLock.lock ();
254+ PtexCachedReader* reader = _openFiles.pop ();
255+ _mruLock.unlock ();
256+
257+ if (!reader) {
258+ // no inactive open file available to close
259+ break ;
260+ }
261+ if (reader->tryClose ()) {
262+ --_filesOpen;
265263 }
266264 }
267265}
268266
269267
270- void PtexReaderCache::pruneData ()
268+ void PtexReaderCache::pruneDataIfNeeded ()
271269{
272270 size_t memUsedChangeTotal = 0 ;
273- size_t memUsed = _memUsed;
274- while (memUsed + memUsedChangeTotal > _maxMem) {
271+ while (_memUsed > _maxMem) {
272+ // prune one texture not currently in use, and then check again
273+ _mruLock.lock ();
275274 PtexCachedReader* reader = _activeFiles.pop ();
276- if (!reader) break ;
275+ _mruLock.unlock ();
276+ if (!reader) {
277+ // no inactive texture available to prune
278+ break ;
279+ }
277280 size_t memUsedChange;
278281 if (reader->tryPrune (memUsedChange)) {
279282 // Note: after clearing, memUsedChange is negative
280283 memUsedChangeTotal += memUsedChange;
281284 }
282285 }
283- adjustMemUsed (memUsedChangeTotal);
286+ if (memUsedChangeTotal) {
287+ adjustMemUsed (memUsedChangeTotal);
288+ }
284289}
285290
286291
0 commit comments