1 
2 
3 #include "tfxattributes.h"
4 
5 #include "trenderer.h"
6 #include "tcacheresource.h"
7 #include "tcacheresourcepool.h"
8 
9 #include "tpassivecachemanager.h"
10 
11 //#define USE_SQLITE_HDPOOL
12 
13 /* PRACTICAL EXPLANATION:
14 
15 The TPassiveCacheManager's purpose is that of storing render results from a
16 specified set of fx nodes.
17 
18 When an fx is passed to the manager to be cached, a structure of type FxData is
19 generated for the fx.
20 It is stored inside the manager and ASSOCIATED to the fx through an INDEX key -
21 this one being stored
22 inside the fx data.
23 
24 In particular, the FxData instances contain a PERSISTANT identifier
25 (passiveCacheId) that is saved inside
26 the scene data, a flag specifying the cache status of the fx node (like, if it's
27 enabled or not), and
28 a description of the schematic dag below the associated fx.
29 
30 Now, when a resource request is made to the TPassiveCacheManager, it checks the
31 FxData about the generating
32 fx - if it contains the flag specifying that it must be cached, a resource is
33 allocated (if not already
34 present), a reference to it is stored, and finally the resource is returned.
35 
36 References to interesting resources are stored in a TABLE container, indexed by
37 "rendering context" and
38 fx. A rendering context is hereby intended as a SEQUENCE of render processes
39 where the next render of the
40 sequence is assumed to REPLACE the previous one.
41 We therefore have one context for the swatch viewer, one for File>Preview, one
42 for the Preview Fx of each
43 fx node, and one context for EACH FRAME of the sceneviewer preview (one frame is
44 not supposed to replace
45 another in that case).
46 
47 The table is in practice a map of maps (a kind of 'comb' structure) - where the
48 primary map is associated
49 by render context and the secondary ones by fx. This mean that we are able to
50 address and iterate contexts
51 easier than fxs. Values of the table are set of resources.
52 
53 RESOURCES MAINTENANCE POLICY:
54 
55 As resources use a concrete amount of memory for storage, they should be kept in
56 the resources table only
57 for the time they are supposedly useful to the user. There are 2 ways of dealing
58 with this issue.
59 
60 1) First, we can track scene changes and eliminate those resources that will no
61 longer be accessed due to the
62 applied change. This happens, for example, when a level is being drawn, fxs are
63 inserted, moved or removed.
64 
65 Level changes are delivered immediately to the ::invalidateLevel(..) method,
66 which removes all resources
67 whose name contains the level's name. Unfortunately, this cannot be done at
68 frame precision (ie you cannot
69 invalidate a single frame of the level, but ALL the level).
70 
71 Xsheet (schematic) changes are tracked through the schematic node description
72 stored inside the FxData structure.
73 Once one such change happens, all resources update their description - if that
74 changes, the associated resources
75 are released.
76 
77 The same schematic description is used to track and release resources affected
78 by changes on a downstream fx's
79 parameters.
80 
81 There are also scene changes that are inherently hard to track or intercept. For
82 example, pegbar affines changes,
83 fx nodes expressions referencing data not directly connected to the fx, and
84 possibly others. These are currently
85 NOT handled by direct tracking.
86 
87 2) As there may be resources which escape the resource control by point (1), we
88 need some extra control
89 policies. Here they are:
90 
91 We assume that the pool of resources accessed by render processes of a same
92 render context should be CONSTANT
93 IF NO SCENE CHANGE HAPPENS. In other words, we are guessing that only those
94 resources used in the last
95 rendering will be used in the next. Resources accessed in a render but NOT in
96 the next (of the same context)
97 are released.
98 
99 However, it could be that the sequence of render processes from a context is
100 halted from a certain moment on.
101 In that case, it is a waste to keep the resources accessed by its last render if
102 no new render will ever take
103 place. We then assume further that a rendering context can be ENABLED or
104 DISABLED - when a render context is
105 enabled, it will most likely have a next render - and therefore can keep its
106 resources in memory.
107 Once a context is DISABLED, it moves the resources to a TEMPORARY context.
108 
109 Resources in the temporary context are those 'on their way for release'. They
110 will be KEPT only if the
111 next rendering - INDEPENDENTLY FROM THE RENDER CONTEXT - requires them (in this
112 case, they will be adopted
113 by the new context). This is necessary since context disables typically happen
114 when a preview window closes.
115 It is not unfrequent that users close the preview window, modify the scene, and
116 then restore the preview.
117 
118 CONSIDERATIONS:
119 
120 * The File>Render generates NO CONTEXT - and therefore does NOT PASSIVELY CACHE
121 RESOURCES, since it cannot be
122   stated whether it is in the 'enabled' or 'disabled' state. It could be
123 considered coherent with what tcomposer
124   does, by the way...
125 
126 * Our resources maintenance policy ensures that the memory usage should be
127 stable over time - that is, no
128   useless resource is kept in memory.
129   Of course, it is possibly more restrictive than what the user may desire. For
130 example, closing 2 preview
131   windows marks their resources for deletion, but only one of the two restored
132 previews will keep its
133   resources intact...
134 
135 */
136 
137 //*****************************************************************************************
138 //    Preliminaries
139 //*****************************************************************************************
140 
141 //  Local stuff - inlines
142 namespace {
toQRect(const TRect & r)143 inline QRect toQRect(const TRect &r) {
144   return QRect(r.x0, r.y0, r.getLx(), r.getLy());
145 }
toTRect(const QRect & r)146 inline TRect toTRect(const QRect &r) {
147   return TRect(r.left(), r.top(), r.right(), r.bottom());
148 }
149 }
150 
151 //---------------------------------------------------------------------------
152 
getNotAllowingAncestor(TFx * fx)153 TFx *TPassiveCacheManager::getNotAllowingAncestor(TFx *fx) {
154   // Trace all output ports
155   int outputPortsCount = fx->getOutputConnectionCount();
156   /*if(!outputPortsCount)   //We have no access to TApp here!!
157 {
158 //It could be a terminal fx. In that case, pass to the xsheet fx
159 FxDag* dag = TApp::instance()->getCurrentXsheet()->getXsheet()->getFxDag();
160 if(dag->getTerminalFxs()->containsFx(fx))
161 return getNotAllowingAncestor(dag->getXsheetFx());
162 }*/
163 
164   // Now, for common ports
165   for (int i = 0; i < outputPortsCount; ++i) {
166     // Find the output Fx and the port connected to our fx
167     TFxPort *port    = fx->getOutputConnection(i);
168     TRasterFx *outFx = static_cast<TRasterFx *>(port->getOwnerFx());
169 
170     int portIdx, portsCount = outFx->getInputPortCount();
171     for (portIdx = 0; portIdx < portsCount; ++portIdx)
172       if (outFx->getInputPort(portIdx) == port) break;
173     assert(portIdx < portsCount);
174 
175     if (!outFx->allowUserCacheOnPort(portIdx)) return outFx;
176 
177     TFx *naAncestor = getNotAllowingAncestor(outFx);
178     if (naAncestor) return naAncestor;
179   }
180 
181   return 0;
182 }
183 
184 //*****************************************************************************************
185 //    Resources Container Definition
186 //*****************************************************************************************
187 
188 template <typename RowKey, typename ColKey, typename Val>
189 class Table {
190 public:
191   typedef typename std::map<ColKey, Val> Row;
192 
193 private:
194   std::map<RowKey, Row> m_table;
195 
196   friend class Iterator;
197   friend class ColIterator;
198 
199 public:
200   typedef typename std::map<RowKey, Row>::iterator RowsIterator;
201 
202   class Iterator {
203   protected:
204     Table *m_table;
205     RowsIterator m_rowIt;
206     typename Row::iterator m_it;
207 
208     friend class Table;
Iterator(Table * table)209     Iterator(Table *table) : m_table(table) {}
210 
makeConsistent()211     virtual void makeConsistent() {
212       if (m_it == m_rowIt->second.end()) {
213         if (++m_rowIt == m_table->m_table.end()) return;
214         m_it = m_rowIt->second.begin();
215       }
216     }
217 
218   public:
row()219     const RowKey &row() { return m_rowIt->first; }
col()220     const ColKey &col() { return m_it->first; }
221 
operator ++()222     virtual void operator++() {
223       ++m_it;
224       makeConsistent();
225     }
226 
operator bool()227     virtual operator bool() { return m_rowIt != m_table->m_table.end(); }
228 
operator *()229     Val &operator*() { return m_it->second; }
operator ->()230     Val *operator->() { return &m_it->second; }
231 
operator ==(const Iterator & it)232     bool operator==(const Iterator &it) { return m_it == it.m_it; }
233 
operator !=(const Iterator & it)234     bool operator!=(const Iterator &it) { return !operator==(it); }
235   };
236 
237   class ColIterator final : public Iterator {
238     ColKey m_colKey;
239 
240     friend class Table;
ColIterator(Table * table,const ColKey & c)241     ColIterator(Table *table, const ColKey &c) : Iterator(table), m_colKey(c) {}
242 
makeConsistent()243     void makeConsistent() override {
244       Iterator::m_rowIt = Iterator::m_rowIt;
245       while (Iterator::m_rowIt != Iterator::m_table->m_table.end()) {
246         Iterator::m_it = Iterator::m_rowIt->second.find(m_colKey);
247         if (Iterator::m_it != Iterator::m_rowIt->second.end()) break;
248         ++Iterator::m_rowIt;
249       }
250     }
251 
252   public:
operator ++()253     void operator++() override {
254       ++Iterator::m_rowIt;
255       makeConsistent();
256     }
257   };
258 
259   class RowIterator final : public Iterator {
260     friend class Table;
RowIterator(Table * table)261     RowIterator(Table *table) : Iterator(table) {}
262 
makeConsistent()263     void makeConsistent() override {}
264 
265   public:
RowIterator(const RowsIterator rowIt)266     RowIterator(const RowsIterator rowIt) : Iterator(0) {
267       Iterator::m_rowIt = rowIt;
268       Iterator::m_it    = rowIt->second.begin();
269     }
270 
operator ++()271     void operator++() override { ++Iterator::m_it; }
operator bool()272     operator bool() override {
273       return Iterator::m_it != Iterator::m_rowIt->second.end();
274     }
275   };
276 
277 public:
Table()278   Table() {}
~Table()279   ~Table() {}
280 
rows()281   std::map<RowKey, Row> &rows() { return m_table; }
282 
begin()283   Iterator begin() {
284     Iterator result(this);
285     result.m_rowIt = m_table.begin();
286     if (result.m_rowIt != m_table.end())
287       result.m_it = result.m_rowIt->second.begin();
288     return result;
289   }
290 
rowBegin(const RowKey & row)291   RowIterator rowBegin(const RowKey &row) {
292     RowIterator result(this);
293     result.m_rowIt = m_table.find(row);
294     if (result.m_rowIt != m_table.end())
295       result.m_it = result.m_rowIt->second.begin();
296     return result;
297   }
298 
colBegin(const ColKey & col)299   ColIterator colBegin(const ColKey &col) {
300     ColIterator result(this, col);
301     result.m_rowIt = m_table.begin();
302     result.makeConsistent();
303     return result;
304   }
305 
value(const RowKey & r,const ColKey & c)306   Val &value(const RowKey &r, const ColKey &c) { return m_table[r][c]; }
307 
insert(const RowKey & r,const ColKey & c,const Val & val)308   Iterator insert(const RowKey &r, const ColKey &c, const Val &val) {
309     Iterator result(this);
310     result.m_rowIt = m_table.insert(std::make_pair(r, Row())).first;
311     result.m_it = result.m_rowIt->second.insert(std::make_pair(c, val)).first;
312     return result;
313   }
314 
erase(const Iterator & it)315   Iterator erase(const Iterator &it) {
316     Iterator result(it);
317     Row &row = it.m_rowIt->second;
318     ++result.m_it;
319     row.erase(it.m_it);
320     if (result.m_it == row.end() && row.empty()) {
321       result.makeConsistent();
322       m_table.erase(it.m_rowIt);
323       return result;
324     }
325 
326     result.makeConsistent();
327     return result;
328   }
329 
erase(const ColKey & c)330   void erase(const ColKey &c) {
331     ColIterator it(colBegin(c));
332     while (it) {
333       RowsIterator rowIt = it.m_rowIt;
334       rowIt->second.erase(it.m_it);
335       ++it;
336       if (rowIt->second.empty()) m_table.erase(rowIt);
337     }
338   }
339 
erase(const RowKey & r)340   void erase(const RowKey &r) { m_table.erase(r); }
341 
clear()342   void clear() { m_table.clear(); }
343 };
344 
345 //--------------------------------------------------------------------------
346 
347 struct LockedResourceP {
348   TCacheResourceP m_resource;
349 
LockedResourcePLockedResourceP350   LockedResourceP(const TCacheResourceP &resource) : m_resource(resource) {
351     m_resource->addLock();
352   }
353 
LockedResourcePLockedResourceP354   LockedResourceP(const LockedResourceP &resource)
355       : m_resource(resource.m_resource) {
356     m_resource->addLock();
357   }
358 
~LockedResourcePLockedResourceP359   ~LockedResourceP() { m_resource->releaseLock(); }
360 
operator =LockedResourceP361   LockedResourceP &operator=(const LockedResourceP &src) {
362     src.m_resource->addLock();
363     if (m_resource) m_resource->releaseLock();
364     m_resource = src.m_resource;
365     return *this;
366   }
367 
operator boolLockedResourceP368   operator bool() const { return m_resource; }
369 
operator <LockedResourceP370   bool operator<(const LockedResourceP &resource) const {
371     return m_resource < resource.m_resource;
372   }
373 
operator ->LockedResourceP374   TCacheResource *operator->() const { return m_resource.getPointer(); }
operator *LockedResourceP375   TCacheResource &operator*() const { return *m_resource.getPointer(); }
376 };
377 
378 typedef Table<std::string, int, std::set<LockedResourceP>> ResourcesTable;
379 
380 //--------------------------------------------------------------------------
381 
382 class TPassiveCacheManager::ResourcesContainer {
383   ResourcesTable m_resources;
384 
385 public:
ResourcesContainer()386   ResourcesContainer() {}
~ResourcesContainer()387   ~ResourcesContainer() {}
388 
getTable()389   ResourcesTable &getTable() { return m_resources; }
390 };
391 
392 //*****************************************************************************************
393 //    FxData implementation
394 //*****************************************************************************************
395 
FxData()396 TPassiveCacheManager::FxData::FxData()
397     : m_storageFlag(0), m_passiveCacheId(0) {}
398 
399 //-------------------------------------------------------------------------
400 
~FxData()401 TPassiveCacheManager::FxData::~FxData() {}
402 
403 //*****************************************************************************************
404 //    Manager generator
405 //*****************************************************************************************
406 
407 //=======================================
408 //    TPassiveCacheManagerGenerator
409 //---------------------------------------
410 
411 class TPassiveCacheManagerGenerator final
412     : public TRenderResourceManagerGenerator {
operator ()(void)413   TRenderResourceManager *operator()(void) override {
414     // return new TPassiveCacheManager;
415     return TPassiveCacheManager::instance();
416   }
417 };
418 
MANAGER_FILESCOPE_DECLARATION_DEP(TPassiveCacheManager,TPassiveCacheManagerGenerator,TFxCacheManager::deps ())419 MANAGER_FILESCOPE_DECLARATION_DEP(TPassiveCacheManager,
420                                   TPassiveCacheManagerGenerator,
421                                   TFxCacheManager::deps())
422 
423 //*****************************************************************************************
424 //    Implementation
425 //*****************************************************************************************
426 
427 TPassiveCacheManager::TPassiveCacheManager()
428 #ifdef USE_SQLITE_HDPOOL
429     : m_currStorageFlag(ON_DISK)
430 #else
431     : m_currStorageFlag(IN_MEMORY)
432 #endif
433     , m_enabled(true)
434     , m_descriptorCallback(0)
435     , m_mutex(QMutex::Recursive)
436     , m_resources(new ResourcesContainer) {
437   reset();
438 }
439 
440 //-------------------------------------------------------------------------
441 
~TPassiveCacheManager()442 TPassiveCacheManager::~TPassiveCacheManager() { delete m_resources; }
443 
444 //-------------------------------------------------------------------------
445 
instance()446 TPassiveCacheManager *TPassiveCacheManager::instance() {
447   static TPassiveCacheManager theInstance;
448   return &theInstance;
449 }
450 
451 //-------------------------------------------------------------------------
452 
setContextName(unsigned long renderId,const std::string & name)453 void TPassiveCacheManager::setContextName(unsigned long renderId,
454                                           const std::string &name) {
455   QMutexLocker locker(&m_mutex);
456 
457   // Retrieve the context data if already present
458   std::map<std::string, UCHAR>::iterator it = m_contextNames.find(name);
459   if (it == m_contextNames.end())
460     it = m_contextNames.insert(std::make_pair(name, 0)).first;
461 
462   it->second = !it->second;
463   m_contextNamesByRenderId.insert(
464       std::make_pair(renderId, name + "%" + std::to_string(it->second)));
465 }
466 
467 //-------------------------------------------------------------------------
468 
getContextName()469 std::string TPassiveCacheManager::getContextName() {
470   QMutexLocker locker(&m_mutex);
471 
472   // First, search the context name
473   std::map<unsigned long, std::string>::iterator it =
474       m_contextNamesByRenderId.find(TRenderer::renderId());
475 
476   if (it == m_contextNamesByRenderId.end()) return "";
477 
478   return it->second;
479 }
480 
481 //-------------------------------------------------------------------------
482 
setEnabled(bool enabled)483 void TPassiveCacheManager::setEnabled(bool enabled) { m_enabled = enabled; }
484 
485 //-------------------------------------------------------------------------
486 
isEnabled() const487 bool TPassiveCacheManager::isEnabled() const { return m_enabled; }
488 
489 //-------------------------------------------------------------------------
490 
setStorageMode(StorageFlag mode)491 void TPassiveCacheManager::setStorageMode(StorageFlag mode) {
492   m_currStorageFlag = mode;
493 }
494 
495 //-------------------------------------------------------------------------
496 
getStorageMode() const497 TPassiveCacheManager::StorageFlag TPassiveCacheManager::getStorageMode() const {
498   return m_currStorageFlag;
499 }
500 
501 //-----------------------------------------------------------------------------------
502 
setTreeDescriptor(TreeDescriptor callback)503 void TPassiveCacheManager::setTreeDescriptor(TreeDescriptor callback) {
504   m_descriptorCallback = callback;
505 }
506 
507 //-----------------------------------------------------------------------------------
508 
getNewPassiveCacheId()509 int TPassiveCacheManager::getNewPassiveCacheId() {
510   return ++m_currentPassiveCacheId;
511 }
512 
513 //-----------------------------------------------------------------------------------
514 
updatePassiveCacheId(int id)515 int TPassiveCacheManager::updatePassiveCacheId(int id) {
516   if (m_updatingPassiveCacheIds)
517     m_currentPassiveCacheId = std::max(m_currentPassiveCacheId, id);
518   else
519     id = getNewPassiveCacheId();
520 
521   return id;
522 }
523 
524 //-----------------------------------------------------------------------------------
525 
onSceneLoaded()526 void TPassiveCacheManager::onSceneLoaded() {
527   m_updatingPassiveCacheIds = false;
528 
529 // Initialize the fxs tree description. This was not possible before, as the
530 // scene was yet incomplete (in loading state).
531 #ifndef USE_SQLITE_HDPOOL
532   unsigned int count = m_fxDataVector.size();
533   for (unsigned int i = 0; i < count; ++i) {
534     FxData &data = m_fxDataVector[i];
535     (*m_descriptorCallback)(data.m_treeDescription, data.m_fx);
536   }
537 #endif
538 }
539 
540 //-----------------------------------------------------------------------------------
541 
touchFxData(int & idx)542 void TPassiveCacheManager::touchFxData(int &idx) {
543   if (idx >= 0) return;
544 
545   QMutexLocker locker(&m_mutex);
546 
547   m_fxDataVector.push_back(FxData());
548   idx = m_fxDataVector.size() - 1;
549 }
550 
551 //-----------------------------------------------------------------------------------
552 
declareCached(TFx * fx,int passiveCacheId)553 int TPassiveCacheManager::declareCached(TFx *fx, int passiveCacheId) {
554   int &idx = fx->getAttributes()->passiveCacheDataIdx();
555   touchFxData(idx);
556 
557   FxData &data          = m_fxDataVector[idx];
558   data.m_fx             = fx;
559   data.m_storageFlag    = m_currStorageFlag;
560   data.m_passiveCacheId = updatePassiveCacheId(passiveCacheId);
561 
562   return idx;
563 }
564 
565 //-------------------------------------------------------------------------
566 
reset()567 void TPassiveCacheManager::reset() {
568   m_updatingPassiveCacheIds = true;
569   m_currentPassiveCacheId   = 0;
570   m_fxDataVector.clear();
571   m_resources->getTable().clear();
572 }
573 
574 //-------------------------------------------------------------------------
575 
cacheEnabled(TFx * fx)576 bool TPassiveCacheManager::cacheEnabled(TFx *fx) {
577   int idx = fx->getAttributes()->passiveCacheDataIdx();
578   if (idx < 0) return false;
579 
580   assert(idx < (int)m_fxDataVector.size());
581 
582   QMutexLocker locker(&m_mutex);
583 
584   return m_fxDataVector[idx].m_storageFlag > 0;
585 }
586 
587 //-------------------------------------------------------------------------
588 
getPassiveCacheId(TFx * fx)589 int TPassiveCacheManager::getPassiveCacheId(TFx *fx) {
590   int idx = fx->getAttributes()->passiveCacheDataIdx();
591   if (idx < 0) return 0;
592 
593   // This needs not be mutex locked
594 
595   assert(idx < (int)m_fxDataVector.size());
596   return m_fxDataVector[idx].m_passiveCacheId;
597 }
598 
599 //-------------------------------------------------------------------------
600 
getStorageMode(TFx * fx)601 TPassiveCacheManager::StorageFlag TPassiveCacheManager::getStorageMode(
602     TFx *fx) {
603   int idx = fx->getAttributes()->passiveCacheDataIdx();
604   if (idx < 0) return NONE;
605 
606   QMutexLocker locker(&m_mutex);
607 
608   return (StorageFlag)m_fxDataVector[idx].m_storageFlag;
609 }
610 
611 //-------------------------------------------------------------------------
612 
enableCache(TFx * fx)613 void TPassiveCacheManager::enableCache(TFx *fx) {
614   int &idx = fx->getAttributes()->passiveCacheDataIdx();
615   touchFxData(idx);
616 
617   FxData &data = m_fxDataVector[idx];
618 
619   QMutexLocker locker(&m_mutex);
620 
621 #ifdef DIAGNOSTICS
622   DIAGNOSTICS_STR("#activity.txt | " + QTime::currentTime().toString() + " " +
623                   QString("Enable Cache"));
624 #endif
625 
626   StorageFlag flag = getStorageMode();
627   if (flag) {
628     UCHAR &storedFlag = data.m_storageFlag;
629     UCHAR oldFlag     = storedFlag;
630 
631     storedFlag |= flag;
632 
633     if (data.m_passiveCacheId == 0)
634       data.m_passiveCacheId = getNewPassiveCacheId();
635 
636     if ((storedFlag & ON_DISK) && !(oldFlag & ON_DISK)) {
637       ResourcesTable::ColIterator it =
638           m_resources->getTable().colBegin(data.m_passiveCacheId);
639       for (; it; ++it) {
640         std::set<LockedResourceP> &resources = *it;
641 
642         std::set<LockedResourceP>::iterator jt;
643         for (jt = resources.begin(); jt != resources.end(); ++jt)
644           (*jt)->enableBackup();
645       }
646     }
647 
648 #ifndef USE_SQLITE_HDPOOL
649     if ((storedFlag & IN_MEMORY) && !(oldFlag & IN_MEMORY)) {
650       data.m_fx = fx;
651       (*m_descriptorCallback)(data.m_treeDescription, data.m_fx);
652     }
653 #endif
654   }
655 }
656 
657 //-------------------------------------------------------------------------
658 
disableCache(TFx * fx)659 void TPassiveCacheManager::disableCache(TFx *fx) {
660   int idx = fx->getAttributes()->passiveCacheDataIdx();
661   if (idx < 0) return;
662 
663   FxData &data = m_fxDataVector[idx];
664 
665   QMutexLocker locker(&m_mutex);
666 
667 #ifdef DIAGNOSTICS
668   DIAGNOSTICS_STR("#activity.txt | " + QTime::currentTime().toString() + " " +
669                   QString("Disable Cache"));
670 #endif
671 
672   StorageFlag flag = getStorageMode();
673   if (flag) {
674     UCHAR &storedFlag = data.m_storageFlag;
675     UCHAR oldFlag     = storedFlag;
676 
677     storedFlag &= ~flag;
678 
679     if ((oldFlag & IN_MEMORY) && !(storedFlag & IN_MEMORY)) {
680       m_resources->getTable().erase(data.m_passiveCacheId);
681 
682       data.m_fx              = TFxP();
683       data.m_treeDescription = "";
684     }
685 
686 #ifdef USE_SQLITE_HDPOOL
687     if ((oldFlag & ON_DISK) && !(storedFlag & ON_DISK))
688       TCacheResourcePool::instance()->releaseReferences(
689           "P" + QString::number(data.m_passiveCacheId));
690 #endif
691   }
692 }
693 
694 //-------------------------------------------------------------------------
695 
toggleCache(TFx * fx)696 void TPassiveCacheManager::toggleCache(TFx *fx) {
697   int &idx = fx->getAttributes()->passiveCacheDataIdx();
698   touchFxData(idx);
699 
700   FxData &data = m_fxDataVector[idx];
701 
702   QMutexLocker locker(&m_mutex);
703 
704   StorageFlag flag = getStorageMode();
705   if (flag) {
706     UCHAR &storedFlag = data.m_storageFlag;
707     UCHAR oldFlag     = storedFlag;
708 
709     storedFlag ^= flag;
710 
711 #ifdef DIAGNOSTICS
712     DIAGNOSTICS_STR("#activity.txt | " + QTime::currentTime().toString() + " " +
713                     QString("Toggle Cache (now ") +
714                     ((storedFlag & IN_MEMORY) ? "enabled)" : "disabled)"));
715 #endif
716 
717     if (data.m_passiveCacheId == 0)
718       data.m_passiveCacheId = getNewPassiveCacheId();
719 
720     if ((storedFlag & ON_DISK) && !(oldFlag & ON_DISK)) {
721       ResourcesTable::ColIterator it =
722           m_resources->getTable().colBegin(data.m_passiveCacheId);
723       for (; it; ++it) {
724         std::set<LockedResourceP> &resources = *it;
725 
726         std::set<LockedResourceP>::iterator jt;
727         for (jt = resources.begin(); jt != resources.end(); ++jt)
728           (*jt)->enableBackup();
729       }
730     }
731 
732     // Implementa la versione contraria - eliminazione dell'fx nell'hdPool...
733     // Metti anche questo in versione ritardata con flush... Il flush e' da
734     // unificare...
735     // e magari da spostare direttamente nell'hdPool
736 
737     if ((oldFlag & IN_MEMORY) && !(storedFlag & IN_MEMORY)) {
738       m_resources->getTable().erase(data.m_passiveCacheId);
739 
740       data.m_fx              = TFxP();
741       data.m_treeDescription = "";
742     }
743 
744 #ifndef USE_SQLITE_HDPOOL
745     if ((storedFlag & IN_MEMORY) && !(oldFlag & IN_MEMORY)) {
746       data.m_fx = fx;
747       (*m_descriptorCallback)(data.m_treeDescription, data.m_fx);
748     }
749 #endif
750 
751 #ifdef USE_SQLITE_HDPOOL
752     if ((oldFlag & ON_DISK) && !(storedFlag & ON_DISK))
753       TCacheResourcePool::instance()->releaseReferences(
754           "P" + QString::number(data.m_passiveCacheId));
755 #endif
756   }
757 }
758 
759 //-------------------------------------------------------------------------
760 
invalidateLevel(const std::string & levelName)761 void TPassiveCacheManager::invalidateLevel(const std::string &levelName) {
762   QMutexLocker locker(&m_mutex);
763 
764   // Traverse the managed resources for passed levelName.
765   ResourcesTable &table       = m_resources->getTable();
766   ResourcesTable::Iterator it = table.begin();
767   while (it) {
768     std::set<LockedResourceP> &resources = *it;
769     std::set<LockedResourceP>::iterator jt, kt;
770     for (jt = resources.begin(); jt != resources.end();) {
771       if ((*jt)->getName().find(levelName) != std::string::npos) {
772         kt = jt++;
773         it->erase(kt);
774       } else
775         ++jt;
776     }
777 
778     if (resources.empty())
779       it = table.erase(it);
780     else
781       ++it;
782   }
783 
784 #ifdef USE_SQLITE_HDPOOL
785   // Store the level name until the invalidation is forced
786   m_invalidatedLevels.insert(levelName);
787 #endif
788 }
789 
790 //-------------------------------------------------------------------------
791 
forceInvalidate()792 void TPassiveCacheManager::forceInvalidate() {
793 #ifdef USE_SQLITE_HDPOOL
794   TCacheResourcePool *pool = TCacheResourcePool::instance();
795 
796   // Clear all invalidated levels from the resource pool
797   std::set<std::string>::iterator it;
798   for (it = m_invalidatedLevels.begin(); it != m_invalidatedLevels.end(); ++it)
799     pool->clearKeyword(*it);
800 
801   m_invalidatedLevels.clear();
802 #endif
803 }
804 
805 //-------------------------------------------------------------------------
806 
807 // Generate the fx's tree description. If it is contained in one of those
808 // stored with cached fxs, release their associated resources.
onFxChanged(const TFxP & fx)809 void TPassiveCacheManager::onFxChanged(const TFxP &fx) {
810 #ifndef USE_SQLITE_HDPOOL
811 
812   std::string fxTreeDescription;
813   (*m_descriptorCallback)(fxTreeDescription, fx);
814 
815   unsigned int count = m_fxDataVector.size();
816   for (unsigned int i = 0; i < count; ++i) {
817     FxData &data = m_fxDataVector[i];
818 
819     if (!data.m_fx) continue;
820 
821     if (data.m_treeDescription.find(fxTreeDescription) != std::string::npos)
822       m_resources->getTable().erase(data.m_passiveCacheId);
823   }
824 
825 #endif
826 }
827 
828 //-------------------------------------------------------------------------
829 
830 // Regenerate the tree descriptions of cached fxs. If the new description does
831 // not match the previous one, release the associated resources.
onXsheetChanged()832 void TPassiveCacheManager::onXsheetChanged() {
833 #ifndef USE_SQLITE_HDPOOL
834 
835 #ifdef DIAGNOSTICS
836   DIAGNOSTICS_STR("#activity.txt | " + QTime::currentTime().toString() +
837                   " XSheet changed");
838 #endif
839 
840   unsigned int count = m_fxDataVector.size();
841   for (unsigned int i = 0; i < count; ++i) {
842     FxData &data = m_fxDataVector[i];
843 
844     if (!data.m_fx) continue;
845 
846     std::string newTreeDescription;
847     (*m_descriptorCallback)(newTreeDescription, data.m_fx);
848 
849     if (data.m_treeDescription != newTreeDescription) {
850       m_resources->getTable().erase(data.m_passiveCacheId);
851       data.m_treeDescription = newTreeDescription;
852     }
853   }
854 
855 #endif
856 }
857 
858 //-------------------------------------------------------------------------
859 
getResource(TCacheResourceP & resource,const std::string & alias,const TFxP & fx,double frame,const TRenderSettings & rs,ResourceDeclaration * resData)860 void TPassiveCacheManager::getResource(TCacheResourceP &resource,
861                                        const std::string &alias, const TFxP &fx,
862                                        double frame, const TRenderSettings &rs,
863                                        ResourceDeclaration *resData) {
864   if (!(m_enabled && fx && rs.m_userCachable)) return;
865 
866   StorageFlag flag = getStorageMode(fx.getPointer());
867   if (flag == NONE) return;
868 
869   std::string contextName(getContextName());
870   if (contextName.empty()) return;
871 
872   // Build a resource if none was passed.
873   if (!resource) resource = TCacheResourceP(alias, true);
874 
875 #ifdef USE_SQLITE_HDPOOL
876   if (flag & ON_DISK) {
877     resource->enableBackup();
878 
879     int passiveCacheId =
880         m_fxDataVector[fx->getAttributes()->passiveCacheDataIdx()]
881             .m_passiveCacheId;
882     TCacheResourcePool::instance()->addReference(
883         resource, "P" + QString::number(passiveCacheId));
884   }
885 #endif
886 
887   if (flag & IN_MEMORY) {
888     QMutexLocker locker(&m_mutex);
889 
890     int passiveCacheId =
891         m_fxDataVector[fx->getAttributes()->passiveCacheDataIdx()]
892             .m_passiveCacheId;
893     m_resources->getTable().value(contextName, passiveCacheId).insert(resource);
894   }
895 }
896 
897 //-------------------------------------------------------------------------
898 
releaseContextNamesWithPrefix(const std::string & prefix)899 void TPassiveCacheManager::releaseContextNamesWithPrefix(
900     const std::string &prefix) {
901   QMutexLocker locker(&m_mutex);
902 
903 #ifdef DIAGNOSTICS
904   DIAGNOSTICS_STR("#activity.txt | " + QTime::currentTime().toString() +
905                   " Release Context Name (" + QString::fromStdString(prefix) +
906                   ")");
907 #endif
908 
909   // Retrieve the context range
910   std::string prefixPlus1 = prefix;
911   prefixPlus1[prefix.size() - 1]++;
912 
913   {
914     std::map<std::string, UCHAR>::iterator it, jt;
915     it = m_contextNames.lower_bound(prefix);
916     jt = m_contextNames.lower_bound(prefixPlus1);
917     m_contextNames.erase(it, jt);
918   }
919 
920   // Transfer to temporary
921   ResourcesTable &table = m_resources->getTable();
922   std::map<std::string, ResourcesTable::Row> &rows =
923       m_resources->getTable().rows();
924 
925   std::map<std::string, ResourcesTable::Row>::iterator it, jt, kt;
926   it = rows.lower_bound(prefix);
927   jt = rows.lower_bound(prefixPlus1);
928 
929   std::string temporaryName("T");
930   for (kt = it; kt != jt; ++kt) {
931     ResourcesTable::RowIterator lt(kt);
932     for (; lt; ++lt)
933       table.value(temporaryName, lt.col()).insert(lt->begin(), lt->end());
934   }
935   rows.erase(it, jt == rows.end() ? rows.lower_bound(prefixPlus1) : jt);
936 }
937 
938 //-------------------------------------------------------------------------
939 
releaseOldResources()940 void TPassiveCacheManager::releaseOldResources() {
941   QMutexLocker locker(&m_mutex);
942 
943   // Release all the resources that were stored in the old render instance of
944   // the
945   // context, PLUS those of the temporary container.
946   // Resources that were held by the TPassiveCacheManager::getResource()
947   // procedure
948   // are now duplicated in a proper row of the table - and will not be freed.
949   std::string contextName(getContextName());
950   if (contextName.empty()) return;
951 
952   char &lastChar = contextName[contextName.size() - 1];
953   lastChar       = '0' + !(lastChar - '0');
954 
955   ResourcesTable &table = m_resources->getTable();
956   table.erase(contextName);
957   table.erase("T");
958 }
959 
960 //-------------------------------------------------------------------------
961 
onRenderInstanceStart(unsigned long renderId)962 void TPassiveCacheManager::onRenderInstanceStart(unsigned long renderId) {
963   TFxCacheManagerDelegate::onRenderInstanceStart(renderId);
964 
965 #ifdef USE_SQLITE_HDPOOL
966   // Force invalidation of levels before the render starts
967   forceInvalidate();
968 #endif
969 }
970 
971 //-------------------------------------------------------------------------
972 
onRenderInstanceEnd(unsigned long renderId)973 void TPassiveCacheManager::onRenderInstanceEnd(unsigned long renderId) {
974   QMutexLocker locker(&m_mutex);
975 
976   releaseOldResources();
977   m_contextNamesByRenderId.erase(renderId);
978 }
979 
980 //-------------------------------------------------------------------------
981 
onRenderStatusEnd(int renderStatus)982 void TPassiveCacheManager::onRenderStatusEnd(int renderStatus) {
983   if (renderStatus == TRenderer::TESTRUN) releaseOldResources();
984 }
985