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