1 
2 
3 #include "trenderer.h"
4 #include "trendererP.h"
5 
6 // TnzCore includes
7 #include "tsystem.h"
8 #include "tthreadmessage.h"
9 #include "tthread.h"
10 #include "tconvert.h"
11 #include "tstream.h"
12 #include "trasterimage.h"
13 #include "trop.h"
14 #include "timagecache.h"
15 #include "tstopwatch.h"
16 
17 // TnzBase includes
18 #include "trenderresourcemanager.h"
19 #include "tpredictivecachemanager.h"
20 
21 // Qt includes
22 #include <QEventLoop>
23 #include <QCoreApplication>
24 #include <QReadWriteLock>
25 #include <QReadLocker>
26 #include <QWriteLocker>
27 #include <QThreadStorage>
28 
29 // Debug
30 //#define DIAGNOSTICS
31 //#include "diagnostics.h"
32 
33 #include <queue>
34 #include <functional>
35 
36 #include <QOffscreenSurface>
37 #include <QSurfaceFormat>
38 #include <QOpenGLContext>
39 #include <QThread>
40 #include <QGuiApplication>
41 
42 using namespace TThread;
43 
44 std::vector<const TFx *> calculateSortedFxs(TRasterFxP rootFx);
45 
46 //================================================================================
47 //    Preliminaries - Anonymous namespace
48 //================================================================================
49 
50 namespace {
51 // TRenderer-thread association storage. It provides TRenderers the per-thread
52 // singleton status from inside a rendering process.
53 QThreadStorage<TRendererImp **> rendererStorage;
54 
55 // Same for render process ids.
56 QThreadStorage<unsigned long *> renderIdsStorage;
57 
58 //-------------------------------------------------------------------------------
59 
60 // Interlacing functions for field-based rendering
interlace(TRasterP f0,const TRasterP & f1,int field)61 inline void interlace(TRasterP f0, const TRasterP &f1, int field) {
62   if (f0->getPixelSize() != f1->getPixelSize())
63     throw TException("interlace: invalid raster combination");
64 
65   assert(f0->getBounds() == f1->getBounds());
66 
67   int outWrapBytes  = f0->getWrap() * f0->getPixelSize();
68   int inWrapBytes   = f1->getWrap() * f1->getPixelSize();
69   int outWrapBytes2 = outWrapBytes * 2;
70   int inWrapBytes2  = inWrapBytes * 2;
71   int rowSize       = f0->getLx() * f0->getPixelSize();
72 
73   f1->lock();
74   f0->lock();
75   UCHAR *rowIn  = f1->getRawData();
76   UCHAR *rowOut = f0->getRawData();
77 
78   if (field) rowIn += inWrapBytes;
79 
80   int count = f0->getLy() / 2;
81   while (--count) {
82     memcpy(rowOut, rowIn, rowSize);
83     rowIn += inWrapBytes2;
84     rowOut += outWrapBytes2;
85   }
86 
87   f1->unlock();
88   f0->unlock();
89 }
90 }  // anonymous namespace
91 
92 //================================================================================
93 //    Preliminaries - output rasters management
94 //================================================================================
95 
96 //===================
97 //    RasterItem
98 //-------------------
99 
100 //! The RasterItem class represents a reusable output raster for rendering
101 //! purposes.
102 //! RasterItems are used as TRenderer's output rasters in order to avoid the
103 //! overhead
104 //! of allocating one raster for each rendered frame.
105 //! Each frame-rendering task will lock a RasterItem as preallocated output
106 //! before starting the
107 //! render, therefore changing the \b RasterItem::m_busy attribute accordingly.
108 //! As each frame is rendered on a separate thread, the number of RasterItems
109 //! that
110 //! TRenderer will allocate depends on the number of rendering threads specified
111 //! to it.
112 
113 //! \sa RasterPool, TRenderer classes
114 
115 class RasterItem {
116   std::string m_rasterId;
117 
118 public:
119   int m_bpp;
120   bool m_busy;
121 
122   //---------------------------------------------------------
123 
RasterItem(const TDimension & size,int bpp,bool busyFlag)124   RasterItem(const TDimension &size, int bpp, bool busyFlag)
125       : m_rasterId(""), m_bpp(bpp), m_busy(busyFlag) {
126     TRasterP raster;
127     if (bpp == 32)
128       raster = TRaster32P(size);
129     else if (bpp == 64)
130       raster = TRaster64P(size);
131     else
132       assert(false);
133 
134     m_rasterId = TImageCache::instance()->getUniqueId();
135     TImageCache::instance()->add(m_rasterId, TRasterImageP(raster));
136   }
137 
138   //---------------------------------------------------------
139 
~RasterItem()140   ~RasterItem() { TImageCache::instance()->remove(m_rasterId); }
141 
142   //---------------------------------------------------------
143 
getRaster() const144   TRasterP getRaster() const {
145     TRasterImageP rimg =
146         (TRasterImageP)TImageCache::instance()->get(m_rasterId, true);
147     return rimg ? rimg->getRaster() : TRasterP();
148   }
149 
150 private:
151   // not implemented
152   RasterItem();
153   RasterItem(const TRaster &RasterItem);
154 };
155 
156 //================================================================================
157 
158 //===================
159 //    RasterPool
160 //-------------------
161 
162 //! Stores a list of RasterItems under TRenderer's requests.
163 class RasterPool {
164   TDimension m_size;
165   int m_bpp;
166 
167   typedef std::list<RasterItem *> RasterRepository;
168   RasterRepository m_rasterRepository;
169 
170   TThread::Mutex m_repositoryLock;
171 
172 public:
RasterPool()173   RasterPool() : m_size(-1, -1) {}
174   ~RasterPool();
175 
176   void setRasterSpecs(const TDimension &size, int bpp);
getRasterSpecs(TDimension & size,int & bpp)177   void getRasterSpecs(TDimension &size, int &bpp) {
178     size = m_size;
179     bpp  = m_bpp;
180   }
181 
182   TRasterP getRaster();
183   TRasterP getRaster(const TDimension &size, int bpp);
184 
185   void releaseRaster(const TRasterP &r);
186 
187   void clear();
188 };
189 
190 //---------------------------------------------------------
191 
clear()192 void RasterPool::clear() {
193   QMutexLocker sl(&m_repositoryLock);
194   clearPointerContainer(m_rasterRepository);
195 }
196 
197 //---------------------------------------------------------
198 
setRasterSpecs(const TDimension & size,int bpp)199 void RasterPool::setRasterSpecs(const TDimension &size, int bpp) {
200   if (size != m_size || bpp != m_bpp) {
201     m_size = size;
202     m_bpp  = bpp;
203     clear();
204   }
205 }
206 
207 //---------------------------------------------------------
208 
getRaster(const TDimension & size,int bpp)209 TRasterP RasterPool::getRaster(const TDimension &size, int bpp) {
210   assert(size == m_size && bpp == m_bpp);
211   return getRaster();
212 }
213 
214 //---------------------------------------------------------
215 
216 //! Returns for the first not-busy raster
getRaster()217 TRasterP RasterPool::getRaster() {
218   QMutexLocker sl(&m_repositoryLock);
219 
220   RasterRepository::iterator it = m_rasterRepository.begin();
221   while (it != m_rasterRepository.end()) {
222     RasterItem *rasItem = *it;
223     if (rasItem->m_busy == false) {
224       TRasterP raster = rasItem->getRaster();
225 
226       if (!raster) {
227         delete rasItem;
228         m_rasterRepository.erase(it++);
229         continue;
230       }
231 
232       rasItem->m_busy = true;
233       raster->clear();
234       return raster;
235     }
236 
237     ++it;
238   }
239 
240   RasterItem *rasItem = new RasterItem(m_size, m_bpp, true);
241   m_rasterRepository.push_back(rasItem);
242 
243   return rasItem->getRaster();
244 }
245 
246 //---------------------------------------------------------
247 
248 //! Cerca il raster \b r in m_rasterRepository; se lo trova setta a \b false il
249 //! campo \b m_busy.
releaseRaster(const TRasterP & r)250 void RasterPool::releaseRaster(const TRasterP &r) {
251   if (!r) return;
252 
253   QMutexLocker sl(&m_repositoryLock);
254   for (RasterRepository::iterator it = m_rasterRepository.begin();
255        it != m_rasterRepository.end(); ++it) {
256     RasterItem *rasItem = *it;
257     if (rasItem->getRaster()->getRawData() == r->getRawData()) {
258       assert(rasItem->m_busy);
259       rasItem->m_busy = false;
260       return;
261     }
262   }
263 }
264 
265 //---------------------------------------------------------
266 
~RasterPool()267 RasterPool::~RasterPool() {
268   /*if (m_rasterRepository.size())
269 TSystem::outputDebug("~RasterPool: itemCount = " + toString
270 ((int)m_rasterRepository.size())+" (should be 0)\n");*/
271 
272   // Release all raster items
273   clear();
274 }
275 
276 //================================================================================
277 //    Internal rendering classes declaration
278 //================================================================================
279 
280 //=====================
281 //    TRendererImp
282 //---------------------
283 
284 class TRendererImp final : public TSmartObject {
285 public:
286   struct RenderInstanceInfos {
287     int m_canceled;
288     int m_activeTasks;
289     int m_status;
290 
RenderInstanceInfosTRendererImp::RenderInstanceInfos291     RenderInstanceInfos()
292         : m_canceled(false), m_activeTasks(0), m_status(TRenderer::IDLE) {}
293   };
294 
295 public:
296   typedef std::vector<TRenderPort *> PortContainer;
297   typedef PortContainer::iterator PortContainerIterator;
298 
299   QReadWriteLock m_portsLock;
300   PortContainer m_ports;
301 
302   QMutex m_renderInstancesMutex;
303   std::map<unsigned long, RenderInstanceInfos> m_activeInstances;
304 
305   //! The renderer Id is a number uniquely associated with a TRenderer instance.
306   static unsigned long m_rendererIdCounter;
307 
308   //! The render Id is a number uniquely associated with a render process
309   //! started
310   //! with the startRendering() method.
311   static unsigned long m_renderIdCounter;
312 
313   unsigned long m_rendererId;
314 
315   Executor m_executor;
316 
317   bool m_precomputingEnabled;
318   RasterPool m_rasterPool;
319 
320   std::vector<TRenderResourceManager *> m_managers;
321 
322   TAtomicVar m_undoneTasks;
323   // std::vector<QEventLoop*> m_waitingLoops;
324   std::vector<bool *> m_waitingLoops;
325 
326   TRasterFxP rootFx;
327 
328   //-------------------------------------------------------------
329 
330   TRendererImp(int nThreads);
331   ~TRendererImp();
332 
333   void startRendering(unsigned long renderId,
334                       const std::vector<TRenderer::RenderData> &renderDatas);
335 
336   void notifyRasterStarted(const TRenderPort::RenderData &rd);
337   void notifyRasterCompleted(const TRenderPort::RenderData &rd);
338   void notifyRasterFailure(const TRenderPort::RenderData &rd, TException &e);
339   void notifyRenderFinished(bool isCanceled = false);
340 
341   void addPort(TRenderPort *port);
342   void removePort(TRenderPort *port);
343 
344   void abortRendering(unsigned long renderId);
345   void stopRendering(bool waitForCompleteStop);
346 
347   bool hasToDie(unsigned long renderId);
348   int getRenderStatus(unsigned long renderId);
349 
enablePrecomputing(bool on)350   void enablePrecomputing(bool on) { m_precomputingEnabled = on; }
isPrecomputingEnabled() const351   bool isPrecomputingEnabled() const { return m_precomputingEnabled; }
352 
setThreadsCount(int nThreads)353   void setThreadsCount(int nThreads) { m_executor.setMaxActiveTasks(nThreads); }
354 
355   inline void declareRenderStart(unsigned long renderId);
356   inline void declareRenderEnd(unsigned long renderId);
357   inline void declareFrameStart(double frame);
358   inline void declareFrameEnd(double frame);
359   inline void declareStatusStart(int renderStatus);
360   inline void declareStatusEnd(int renderStatus);
361 
362   void quitWaitingLoops();
363 };
364 
365 #ifdef _WIN32
366 template class DVAPI TSmartPointerT<TRendererImp>;
367 #endif
368 
369 typedef TSmartPointerT<TRendererImp> TRendererImpP;
370 
371 unsigned long TRendererImp::m_rendererIdCounter = 0;
372 unsigned long TRendererImp::m_renderIdCounter   = 0;
373 
374 //================================================================================
375 
376 //===================
377 //    RenderTask
378 //-------------------
379 
380 class RenderTask final : public TThread::Runnable {
381   std::vector<double> m_frames;
382 
383   unsigned long m_taskId;
384   unsigned long m_renderId;
385 
386   TRendererImpP m_rendererImp;
387 
388   TFxPair m_fx;
389   TPointD m_framePos;
390   TDimension m_frameSize;
391   TRenderSettings m_info;
392 
393   bool m_fieldRender, m_stereoscopic;
394 
395   Mutex m_rasterGuard;
396   TTile m_tileA;  // in normal and field rendering, Rendered at given frame; in
397                   // stereoscopic, rendered left frame
398   TTile m_tileB;  // in  field rendering, rendered at frame + 0.5; in
399                   // stereoscopic, rendered right frame
400 
401 public:
402   RenderTask(unsigned long renderId, unsigned long taskId, double frame,
403              const TRenderSettings &ri, const TFxPair &fx,
404              const TPointD &framePos, const TDimension &frameSize,
405              const TRendererImpP &rendererImp);
406 
~RenderTask()407   ~RenderTask() {}
408 
addFrame(double frame)409   void addFrame(double frame) { m_frames.push_back(frame); }
410 
411   void buildTile(TTile &tile);
412   void releaseTiles();
413 
414   void onFrameStarted();
415   void onFrameCompleted();
416   void onFrameFailed(TException &e);
417 
418   void preRun();
419   void run() override;
420 
taskLoad()421   int taskLoad() override { return 100; }
422 
423   void onFinished(TThread::RunnableP) override;
424 };
425 
426 //================================================================================
427 //    Implementations
428 //================================================================================
429 
430 //==================
431 //    TRenderer
432 //------------------
433 
TRenderer(int nThread)434 TRenderer::TRenderer(int nThread) {
435   m_imp = new TRendererImp(nThread);  // Already adds a ref
436 }
437 
438 //---------------------------------------------------------
439 
TRenderer(TRendererImp * imp)440 TRenderer::TRenderer(TRendererImp *imp) : m_imp(imp) {
441   if (m_imp) m_imp->addRef();
442 }
443 
444 //---------------------------------------------------------
445 
TRenderer(const TRenderer & r)446 TRenderer::TRenderer(const TRenderer &r) : m_imp(r.m_imp) {
447   if (m_imp) m_imp->addRef();
448 }
449 
450 //---------------------------------------------------------
451 
operator =(const TRenderer & r)452 void TRenderer::operator=(const TRenderer &r) {
453   m_imp = r.m_imp;
454   if (m_imp) m_imp->addRef();
455 }
456 
457 //---------------------------------------------------------
458 
~TRenderer()459 TRenderer::~TRenderer() {
460   if (m_imp) m_imp->release();
461 }
462 
463 //---------------------------------------------------------
464 
465 //! The static method is intended for use inside a rendering thread only. It
466 //! returns
467 //! a copy of the eventual TRenderer interface installed on the thread -
468 //! or an empty TRenderer if none happened to be. It can be set using the
469 //! install() and uninstall() methods.
instance()470 TRenderer TRenderer::instance() {
471   TRendererImp **lData = rendererStorage.localData();
472   if (lData) return TRenderer(*lData);
473   return 0;
474 }
475 
476 //---------------------------------------------------------
477 
478 //! Returns the renderer id.
rendererId()479 unsigned long TRenderer::rendererId() { return m_imp->m_rendererId; }
480 
481 //---------------------------------------------------------
482 
483 //! Returns the rendering process id currently running on the invoking
484 //! thread.
renderId()485 unsigned long TRenderer::renderId() {
486   unsigned long *lData = renderIdsStorage.localData();
487   return lData ? *lData : -1;
488 }
489 
490 //---------------------------------------------------------
491 
492 //! Builds and returns an id for starting a new rendering process.
buildRenderId()493 unsigned long TRenderer::buildRenderId() {
494   return TRendererImp::m_renderIdCounter++;
495 }
496 
497 //---------------------------------------------------------
498 
499 //! Returns the renderId that will be used by the next startRendering() call.
500 //! This method can be used to retrieve the renderId of a rendering instance
501 //! before it is actually started - provided that no other render instance
502 //! is launched inbetween.
nextRenderId()503 unsigned long TRenderer::nextRenderId() {
504   return TRendererImp::m_renderIdCounter;
505 }
506 
507 //---------------------------------------------------------
508 
declareRenderStart(unsigned long renderId)509 inline void TRendererImp::declareRenderStart(unsigned long renderId) {
510   // Inform the resource managers
511   for (unsigned int i = 0; i < m_managers.size(); ++i)
512     m_managers[i]->onRenderInstanceStart(renderId);
513 }
514 
515 //! Declares that the render process of passed renderId is about to start.
declareRenderStart(unsigned long renderId)516 void TRenderer::declareRenderStart(unsigned long renderId) {
517   m_imp->declareRenderStart(renderId);
518 }
519 
520 //---------------------------------------------------------
521 
declareRenderEnd(unsigned long renderId)522 inline void TRendererImp::declareRenderEnd(unsigned long renderId) {
523   // Inform the resource managers
524   for (int i = m_managers.size() - 1; i >= 0; --i)
525     m_managers[i]->onRenderInstanceEnd(renderId);
526 }
527 
528 //! Declares that the render process of passed renderId has ended.
declareRenderEnd(unsigned long renderId)529 void TRenderer::declareRenderEnd(unsigned long renderId) {
530   m_imp->declareRenderEnd(renderId);
531 }
532 
533 //---------------------------------------------------------
534 
declareFrameStart(double frame)535 inline void TRendererImp::declareFrameStart(double frame) {
536   // Inform the resource managers
537   for (unsigned int i = 0; i < m_managers.size(); ++i)
538     m_managers[i]->onRenderFrameStart(frame);
539 }
540 
541 //! Declares that render of passed frame is about to start.
declareFrameStart(double frame)542 void TRenderer::declareFrameStart(double frame) {
543   m_imp->declareFrameStart(frame);
544 }
545 
546 //---------------------------------------------------------
547 
declareFrameEnd(double frame)548 inline void TRendererImp::declareFrameEnd(double frame) {
549   // Inform the resource managers
550   for (int i = m_managers.size() - 1; i >= 0; --i)
551     m_managers[i]->onRenderFrameEnd(frame);
552 }
553 
554 //! Declares that render of passed has ended.
declareFrameEnd(double frame)555 void TRenderer::declareFrameEnd(double frame) { m_imp->declareFrameEnd(frame); }
556 
557 //---------------------------------------------------------
558 
declareStatusStart(int renderStatus)559 inline void TRendererImp::declareStatusStart(int renderStatus) {
560   // Inform the resource managers
561   for (unsigned int i = 0; i < m_managers.size(); ++i)
562     m_managers[i]->onRenderStatusStart(renderStatus);
563 }
564 
565 //---------------------------------------------------------
566 
declareStatusEnd(int renderStatus)567 inline void TRendererImp::declareStatusEnd(int renderStatus) {
568   // Inform the resource managers
569   for (int i = m_managers.size() - 1; i >= 0; --i)
570     m_managers[i]->onRenderStatusEnd(renderStatus);
571 }
572 
573 //---------------------------------------------------------
574 
575 //! Installs the specified render process on the invoking thread.
install(unsigned long renderId)576 void TRenderer::install(unsigned long renderId) {
577   m_imp->addRef();
578   rendererStorage.setLocalData(new (TRendererImp *)(m_imp));
579   renderIdsStorage.setLocalData(new unsigned long(renderId));
580 }
581 
582 //---------------------------------------------------------
583 
584 //! Uninstalls any rendering process active on the invoking thread.
uninstall()585 void TRenderer::uninstall() {
586   rendererStorage.setLocalData(0);
587   renderIdsStorage.setLocalData(0);
588   m_imp->release();
589 }
590 
591 //---------------------------------------------------------
592 
getManager(unsigned int id) const593 TRenderResourceManager *TRenderer::getManager(unsigned int id) const {
594   return m_imp->m_managers[id];
595 }
596 
597 //---------------------------------------------------------
598 
enablePrecomputing(bool on)599 void TRenderer::enablePrecomputing(bool on) { m_imp->enablePrecomputing(on); }
600 
601 //---------------------------------------------------------
602 
isPrecomputingEnabled() const603 bool TRenderer::isPrecomputingEnabled() const {
604   return m_imp->isPrecomputingEnabled();
605 }
606 
607 //---------------------------------------------------------
608 
setThreadsCount(int nThreads)609 void TRenderer::setThreadsCount(int nThreads) {
610   m_imp->setThreadsCount(nThreads);
611 }
612 
613 //---------------------------------------------------------
614 
addPort(TRenderPort * port)615 void TRenderer::addPort(TRenderPort *port) { m_imp->addPort(port); }
616 
617 //---------------------------------------------------------
618 
removePort(TRenderPort * port)619 void TRenderer::removePort(TRenderPort *port) { m_imp->removePort(port); }
620 
621 //---------------------------------------------------------
622 
startRendering(double f,const TRenderSettings & info,const TFxPair & actualRoot)623 unsigned long TRenderer::startRendering(double f, const TRenderSettings &info,
624                                         const TFxPair &actualRoot) {
625   assert(f >= 0);
626 
627   std::vector<RenderData> *rds = new std::vector<RenderData>;
628   rds->push_back(RenderData(f, info, actualRoot));
629   return startRendering(rds);
630 }
631 
632 //---------------------------------------------------------
633 
634 //! Queues a rendering event in the main event loop.
635 //! NOTE: The passed pointer is owned by the TRenderer after it is submitted for
636 //! rendering -
637 //! do not delete it later.
startRendering(const std::vector<RenderData> * renderDatas)638 unsigned long TRenderer::startRendering(
639     const std::vector<RenderData> *renderDatas) {
640   if (renderDatas->empty()) {
641     delete renderDatas;
642     return -1;
643   }
644 
645   // Build a new render Id
646   unsigned long renderId = m_imp->m_renderIdCounter++;
647 
648   TRendererStartInvoker::StartInvokerRenderData srd;
649   srd.m_renderId         = renderId;
650   srd.m_renderDataVector = renderDatas;
651   TRendererStartInvoker::instance()->emitStartRender(m_imp, srd);
652 
653   return renderId;
654 }
655 
656 //---------------------------------------------------------
657 
abortRendering(unsigned long renderId)658 void TRenderer::abortRendering(unsigned long renderId) {
659   m_imp->abortRendering(renderId);
660 }
661 
662 //---------------------------------------------------------
663 
stopRendering(bool waitForCompleteStop)664 void TRenderer::stopRendering(bool waitForCompleteStop) {
665   m_imp->stopRendering(waitForCompleteStop);
666 }
667 
668 //---------------------------------------------------------
669 
isAborted(unsigned long renderId) const670 bool TRenderer::isAborted(unsigned long renderId) const {
671   return m_imp->hasToDie(renderId);
672 }
673 
674 //---------------------------------------------------------
675 
getRenderStatus(unsigned long renderId) const676 int TRenderer::getRenderStatus(unsigned long renderId) const {
677   return m_imp->getRenderStatus(renderId);
678 }
679 
680 //================================================================================
681 
682 //=====================
683 //    TRendererImp
684 //---------------------
685 
TRendererImp(int nThreads)686 TRendererImp::TRendererImp(int nThreads)
687     : m_executor()
688     , m_undoneTasks()
689     , m_rendererId(m_rendererIdCounter++)
690     , m_precomputingEnabled(true) {
691   m_executor.setMaxActiveTasks(nThreads);
692 
693   std::vector<TRenderResourceManagerGenerator *> &generators =
694       TRenderResourceManagerGenerator::generators(false);
695 
696   // May be adopted by other TRenderers from now on.
697   addRef();
698 
699   rendererStorage.setLocalData(new (TRendererImp *)(this));
700 
701   unsigned int i;
702   for (i = 0; i < generators.size(); ++i) {
703     TRenderResourceManager *manager = (*generators[i])();
704     if (manager) m_managers.push_back(manager);
705   }
706 
707   rendererStorage.setLocalData(0);
708 }
709 
710 //---------------------------------------------------------
711 
~TRendererImp()712 TRendererImp::~TRendererImp() {
713   rendererStorage.setLocalData(new (TRendererImp *)(this));
714 
715   int i;
716   for (i = m_managers.size() - 1; i >= 0; --i)
717     if (m_managers[i]->renderHasOwnership()) delete m_managers[i];
718 
719   rendererStorage.setLocalData(0);
720 }
721 
722 //---------------------------------------------------------
723 
addPort(TRenderPort * port)724 void TRendererImp::addPort(TRenderPort *port) {
725   QWriteLocker sl(&m_portsLock);
726 
727   PortContainerIterator it = std::find(m_ports.begin(), m_ports.end(), port);
728   if (it == m_ports.end()) m_ports.push_back(port);
729 }
730 
731 //---------------------------------------------------------
732 
removePort(TRenderPort * port)733 void TRendererImp::removePort(TRenderPort *port) {
734   QWriteLocker sl(&m_portsLock);
735 
736   PortContainerIterator it = std::find(m_ports.begin(), m_ports.end(), port);
737   if (it != m_ports.end()) m_ports.erase(it);
738 }
739 
740 //---------------------------------------------------------
741 
hasToDie(unsigned long renderId)742 bool TRendererImp::hasToDie(unsigned long renderId) {
743   QMutexLocker sl(&m_renderInstancesMutex);
744 
745   std::map<unsigned long, RenderInstanceInfos>::iterator it =
746       m_activeInstances.find(renderId);
747   assert(it != m_activeInstances.end());
748   return it == m_activeInstances.end() ? true : it->second.m_canceled;
749 }
750 
751 //---------------------------------------------------------
752 
getRenderStatus(unsigned long renderId)753 int TRendererImp::getRenderStatus(unsigned long renderId) {
754   QMutexLocker sl(&m_renderInstancesMutex);
755 
756   std::map<unsigned long, RenderInstanceInfos>::iterator it =
757       m_activeInstances.find(renderId);
758   assert(it != m_activeInstances.end());
759   return it == m_activeInstances.end() ? true : it->second.m_status;
760 }
761 
762 //---------------------------------------------------------
763 
abortRendering(unsigned long renderId)764 void TRendererImp::abortRendering(unsigned long renderId) {
765   QMutexLocker sl(&m_renderInstancesMutex);
766 
767   std::map<unsigned long, RenderInstanceInfos>::iterator it =
768       m_activeInstances.find(renderId);
769   if (it != m_activeInstances.end()) it->second.m_canceled = true;
770 }
771 
772 //---------------------------------------------------------
773 
stopRendering(bool waitForCompleteStop)774 void TRendererImp::stopRendering(bool waitForCompleteStop) {
775   QMutexLocker sl(&m_renderInstancesMutex);
776 
777   {
778     // Tasks already stop rendering on their own when they don't find their
779     // render ids here.
780     std::map<unsigned long, RenderInstanceInfos>::iterator it;
781     for (it = m_activeInstances.begin(); it != m_activeInstances.end(); ++it)
782       it->second.m_canceled = true;
783   }
784 
785   if (waitForCompleteStop && m_undoneTasks > 0) {
786     // Sometimes, QEventLoop suddenly stops processing slots (especially those
787     // notifications
788     // from active rendering instances) - therefore resulting in a block of the
789     // application.
790     // I've not figured out why (#QTBUG-11649?) - but substituting with a plain
791     // while
792     // seems to do the trick...
793 
794     /*QEventLoop eventLoop;
795 m_waitingLoops.push_back(&eventLoop);
796 eventLoop.exec();*/
797 
798     bool loopQuit = false;
799     m_waitingLoops.push_back(&loopQuit);
800 
801     sl.unlock();
802 
803     while (!loopQuit)
804       QCoreApplication::processEvents(QEventLoop::AllEvents |
805                                       QEventLoop::WaitForMoreEvents);
806   }
807 }
808 
809 //---------------------------------------------------------
810 
quitWaitingLoops()811 void TRendererImp::quitWaitingLoops() {
812   // Make the stopRendering waiting loops quit
813   while (!m_waitingLoops.empty()) {
814     // rendererImp->m_waitingLoops.back()->quit();
815     *m_waitingLoops.back() = true;
816     m_waitingLoops.pop_back();
817   }
818 }
819 
820 //---------------------------------------------------------
821 
notifyRasterStarted(const TRenderPort::RenderData & rd)822 void TRendererImp::notifyRasterStarted(const TRenderPort::RenderData &rd) {
823   // Since notifications may trigger port removals, we always work on a copy of
824   // the ports
825   // vector.
826   TRendererImp::PortContainer portsCopy;
827   {
828     QReadLocker sl(&m_portsLock);
829     portsCopy = m_ports;
830   }
831 
832   for (PortContainerIterator it = portsCopy.begin(); it != portsCopy.end();
833        ++it)
834     (*it)->onRenderRasterStarted(rd);
835 }
836 
837 //---------------------------------------------------------
838 
notifyRasterCompleted(const TRenderPort::RenderData & rd)839 void TRendererImp::notifyRasterCompleted(const TRenderPort::RenderData &rd) {
840   TRendererImp::PortContainer portsCopy;
841   {
842     QReadLocker sl(&m_portsLock);
843     portsCopy = m_ports;
844   }
845 
846   assert(rd.m_rasA);
847 
848   for (PortContainerIterator it = portsCopy.begin(); it != portsCopy.end();
849        ++it)
850     (*it)->onRenderRasterCompleted(rd);
851 }
852 
853 //---------------------------------------------------------
854 
notifyRasterFailure(const TRenderPort::RenderData & rd,TException & e)855 void TRendererImp::notifyRasterFailure(const TRenderPort::RenderData &rd,
856                                        TException &e) {
857   TRendererImp::PortContainer portsCopy;
858   {
859     QReadLocker sl(&m_portsLock);
860     portsCopy = m_ports;
861   }
862 
863   for (PortContainerIterator it = portsCopy.begin(); it != portsCopy.end();
864        ++it)
865     (*it)->onRenderFailure(rd, e);
866 }
867 
868 //---------------------------------------------------------
869 
notifyRenderFinished(bool isCanceled)870 void TRendererImp::notifyRenderFinished(bool isCanceled) {
871   TRendererImp::PortContainer portsCopy;
872   {
873     QReadLocker sl(&m_portsLock);
874     portsCopy = m_ports;
875   }
876 
877   auto sortedFxs = calculateSortedFxs(rootFx);
878   for (auto fx : sortedFxs) {
879     if (fx) const_cast<TFx *>(fx)->callEndRenderHandler();
880   }
881 
882   for (PortContainerIterator it = portsCopy.begin(); it != portsCopy.end();
883        ++it)
884     (*it)->onRenderFinished();
885 }
886 
887 //================================================================================
888 
889 //====================
890 //    TRenderPort
891 //--------------------
892 
TRenderPort()893 TRenderPort::TRenderPort() {}
894 
895 //---------------------------------------------------------
896 
~TRenderPort()897 TRenderPort::~TRenderPort() {}
898 
899 //---------------------------------------------------------
900 
901 //! Setta \b m_renderArea a \b area e pulisce l'istanza corrente di \b
902 //! RasterPool.
setRenderArea(const TRectD & area)903 void TRenderPort::setRenderArea(const TRectD &area) { m_renderArea = area; }
904 
905 //---------------------------------------------------------
906 
907 //! Ritorna \b m_renderArea.
getRenderArea()908 TRectD &TRenderPort::getRenderArea() { return m_renderArea; }
909 
910 //================================================================================
911 
912 //===================
913 //    RenderTask
914 //-------------------
915 
RenderTask(unsigned long renderId,unsigned long taskId,double frame,const TRenderSettings & ri,const TFxPair & fx,const TPointD & framePos,const TDimension & frameSize,const TRendererImpP & rendererImp)916 RenderTask::RenderTask(unsigned long renderId, unsigned long taskId,
917                        double frame, const TRenderSettings &ri,
918                        const TFxPair &fx, const TPointD &framePos,
919                        const TDimension &frameSize,
920                        const TRendererImpP &rendererImp)
921     : m_renderId(renderId)
922     , m_taskId(taskId)
923     , m_info(ri)
924     , m_fx(fx)
925     , m_frameSize(frameSize)
926     , m_framePos(framePos)
927     , m_rendererImp(rendererImp)
928     , m_fieldRender(ri.m_fieldPrevalence != TRenderSettings::NoField)
929     , m_stereoscopic(ri.m_stereoscopic) {
930   m_frames.push_back(frame);
931 
932   // Connect the onFinished slot
933   connect(this, SIGNAL(finished(TThread::RunnableP)), this,
934           SLOT(onFinished(TThread::RunnableP)));
935   connect(this, SIGNAL(exception(TThread::RunnableP)), this,
936           SLOT(onFinished(TThread::RunnableP)));
937 
938   // The shrink info is currently reversed to the settings'affine. Shrink info
939   // in the TRenderSettings
940   // is no longer supported.
941   m_info.m_shrinkX = m_info.m_shrinkY = 1;
942 }
943 
944 //---------------------------------------------------------
945 
preRun()946 void RenderTask::preRun() {
947   TRectD geom(m_framePos, TDimensionD(m_frameSize.lx, m_frameSize.ly));
948 
949   if (m_fx.m_frameA) m_fx.m_frameA->dryCompute(geom, m_frames[0], m_info);
950 
951   if (m_fx.m_frameB)
952     m_fx.m_frameB->dryCompute(
953         geom, m_fieldRender ? m_frames[0] + 0.5 : m_frames[0], m_info);
954 }
955 
956 //---------------------------------------------------------
957 
run()958 void RenderTask::run() {
959   // Retrieve the task's frame
960   assert(!m_frames.empty());
961   double t = m_frames[0];
962 
963   if (m_rendererImp->hasToDie(m_renderId)) {
964     TException e("Render task aborted");
965     onFrameFailed(e);
966     return;
967   }
968 
969   // Install the renderer in current thread
970   rendererStorage.setLocalData(
971       new (TRendererImp *)(m_rendererImp.getPointer()));
972   renderIdsStorage.setLocalData(new unsigned long(m_renderId));
973 
974   // Inform the managers of frame start
975   m_rendererImp->declareFrameStart(t);
976 
977   auto sortedFxs = calculateSortedFxs(m_fx.m_frameA);
978   for (auto fx : sortedFxs) {
979     if (fx) const_cast<TFx *>(fx)->callStartRenderFrameHandler(&m_info, t);
980   }
981 
982   try {
983     onFrameStarted();
984 
985     TStopWatch::global(8).start();
986 
987     if (!m_fieldRender && !m_stereoscopic) {
988       // Common case - just build the first tile
989       buildTile(m_tileA);
990       /*-- 通常はここがFxのレンダリング処理 --*/
991       m_fx.m_frameA->compute(m_tileA, t, m_info);
992     } else {
993       assert(!(m_stereoscopic && m_fieldRender));
994       // Field rendering  or stereoscopic case
995       if (m_stereoscopic) {
996         buildTile(m_tileA);
997         m_fx.m_frameA->compute(m_tileA, t, m_info);
998 
999         buildTile(m_tileB);
1000         m_fx.m_frameB->compute(m_tileB, t, m_info);
1001       }
1002       // if fieldPrevalence, Decide the rendering frames depending on field
1003       // prevalence
1004       else if (m_info.m_fieldPrevalence == TRenderSettings::EvenField) {
1005         buildTile(m_tileA);
1006         m_fx.m_frameA->compute(m_tileA, t, m_info);
1007 
1008         buildTile(m_tileB);
1009         m_fx.m_frameB->compute(m_tileB, t + 0.5, m_info);
1010       } else {
1011         buildTile(m_tileB);
1012         m_fx.m_frameA->compute(m_tileB, t, m_info);
1013 
1014         buildTile(m_tileA);
1015         m_fx.m_frameB->compute(m_tileA, t + 0.5, m_info);
1016       }
1017     }
1018 
1019     TStopWatch::global(8).stop();
1020 
1021     onFrameCompleted();
1022   } catch (TException &e) {
1023     onFrameFailed(e);
1024   } catch (...) {
1025     TException ex("Unknown render exception");
1026     onFrameFailed(ex);
1027   }
1028 
1029   // Inform the managers of frame end
1030   m_rendererImp->declareFrameEnd(t);
1031 
1032   // Uninstall the renderer from current thread
1033   rendererStorage.setLocalData(0);
1034   renderIdsStorage.setLocalData(0);
1035 
1036   for (auto fx : sortedFxs) {
1037     if (fx) const_cast<TFx *>(fx)->callEndRenderFrameHandler(&m_info, t);
1038   }
1039 }
1040 
1041 //---------------------------------------------------------
1042 
buildTile(TTile & tile)1043 void RenderTask::buildTile(TTile &tile) {
1044   tile.m_pos = m_framePos;
1045   tile.setRaster(
1046       m_rendererImp->m_rasterPool.getRaster(m_frameSize, m_info.m_bpp));
1047 }
1048 
1049 //---------------------------------------------------------
1050 
releaseTiles()1051 void RenderTask::releaseTiles() {
1052   m_rendererImp->m_rasterPool.releaseRaster(m_tileA.getRaster());
1053   m_tileA.setRaster(TRasterP());
1054   if (m_fieldRender || m_stereoscopic) {
1055     m_rendererImp->m_rasterPool.releaseRaster(m_tileB.getRaster());
1056     m_tileB.setRaster(TRasterP());
1057   }
1058 }
1059 
1060 //---------------------------------------------------------
1061 
onFrameStarted()1062 void RenderTask::onFrameStarted() {
1063   TRenderPort::RenderData rd(m_frames, m_info, 0, 0, m_renderId, m_taskId);
1064   m_rendererImp->notifyRasterStarted(rd);
1065 }
1066 
1067 //---------------------------------------------------------
1068 
onFrameCompleted()1069 void RenderTask::onFrameCompleted() {
1070   TRasterP rasA(m_tileA.getRaster());
1071   TRasterP rasB(m_tileB.getRaster());
1072 
1073   if (m_fieldRender) {
1074     assert(rasB);
1075 
1076     double t = m_frames[0];
1077 
1078     int f = (m_info.m_fieldPrevalence == TRenderSettings::EvenField) ? 0 : 1;
1079     interlace(rasA, rasB, f);
1080     rasB = TRasterP();
1081   }
1082 
1083   TRenderPort::RenderData rd(m_frames, m_info, rasA, rasB, m_renderId,
1084                              m_taskId);
1085   m_rendererImp->notifyRasterCompleted(rd);
1086 }
1087 
1088 //---------------------------------------------------------
1089 
onFrameFailed(TException & e)1090 void RenderTask::onFrameFailed(TException &e) {
1091   // TRasterP evenRas(m_evenTile.getRaster());
1092 
1093   TRenderPort::RenderData rd(m_frames, m_info, m_tileA.getRaster(),
1094                              m_tileB.getRaster(), m_renderId, m_taskId);
1095   m_rendererImp->notifyRasterFailure(rd, e);
1096 }
1097 
1098 //---------------------------------------------------------
1099 
onFinished(TThread::RunnableP)1100 void RenderTask::onFinished(TThread::RunnableP) {
1101   TRendererImp *rendererImp = m_rendererImp.getPointer();
1102   --rendererImp->m_undoneTasks;
1103 
1104   // Tiles release back to the Raster Pool happens in the main thread, after all
1105   // possible
1106   // signals emitted in the onFrameCompleted/Failed notifications have been
1107   // resolved, thus
1108   // ensuring that no other rendering thread owns the rasters before them.
1109   releaseTiles();
1110 
1111   // Update the render instance status
1112   bool instanceExpires = false;
1113   bool isCanceled      = false;
1114   {
1115     QMutexLocker sl(&rendererImp->m_renderInstancesMutex);
1116     std::map<unsigned long, TRendererImp::RenderInstanceInfos>::iterator it =
1117         rendererImp->m_activeInstances.find(m_renderId);
1118 
1119     if (it != rendererImp->m_activeInstances.end() &&
1120         (--it->second.m_activeTasks) <= 0) {
1121       instanceExpires = true;
1122       isCanceled      = (m_info.m_isCanceled && *m_info.m_isCanceled);
1123       rendererImp->m_activeInstances.erase(m_renderId);
1124       // m_info is freed, don't access further!
1125     }
1126   }
1127 
1128   // If the render instance has just expired
1129   if (instanceExpires) {
1130     /*-- キャンセルされた場合はm_overallRenderedRegionの更新をしない --*/
1131 
1132     // Inform the render ports
1133     rendererImp->notifyRenderFinished(isCanceled);
1134 
1135     // NOTE: This slot is currently invoked on the main thread. It could
1136     // eventually be
1137     // invoked directly on rendering threads, specifying the
1138     // Qt::DirectConnection option -
1139     // but probably there would be no real advantage in doing so...
1140 
1141     // Temporarily install the renderer in current thread
1142     rendererStorage.setLocalData(new (TRendererImp *)(rendererImp));
1143     renderIdsStorage.setLocalData(new unsigned long(m_renderId));
1144 
1145     // Inform the resource managers
1146     rendererImp->declareRenderEnd(m_renderId);
1147 
1148     // Uninstall the temporary
1149     rendererStorage.setLocalData(0);
1150     renderIdsStorage.setLocalData(0);
1151 
1152     rendererImp->m_rasterPool
1153         .clear();  // Isn't this misplaced? Should be in the block
1154   }                // below...
1155 
1156   // If no rendering task (of this or other render instances) is found...
1157   if (rendererImp->m_undoneTasks == 0) {
1158     QMutexLocker sl(&rendererImp->m_renderInstancesMutex);
1159     rendererImp->quitWaitingLoops();
1160   }
1161 }
1162 
1163 //================================================================================
1164 //    Tough Stuff
1165 //================================================================================
1166 
emitStartRender(TRendererImp * renderer,StartInvokerRenderData rd)1167 void TRendererStartInvoker::emitStartRender(TRendererImp *renderer,
1168                                             StartInvokerRenderData rd) {
1169   renderer->addRef();
1170   Q_EMIT startRender(renderer, rd);
1171 }
1172 
1173 //---------------------------------------------------------
1174 
doStartRender(TRendererImp * renderer,StartInvokerRenderData rd)1175 void TRendererStartInvoker::doStartRender(TRendererImp *renderer,
1176                                           StartInvokerRenderData rd) {
1177   renderer->startRendering(rd.m_renderId, *rd.m_renderDataVector);
1178   renderer->release();
1179   delete rd.m_renderDataVector;
1180 }
1181 
calculateSortedFxs(TRasterFxP rootFx)1182 std::vector<const TFx *> calculateSortedFxs(TRasterFxP rootFx) {
1183   std::map<const TFx *, std::set<const TFx *>> E; /* 辺の情報 */
1184   std::set<const TFx *> Sources; /* 入次数0のノード群 */
1185 
1186   std::queue<const TFx *> Q;
1187   Q.push(rootFx.getPointer());
1188 
1189   E[rootFx.getPointer()] = std::set<const TFx *>();
1190 
1191   while (!Q.empty()) {
1192     const TFx *vptr = Q.front();
1193     Q.pop();
1194     if (!vptr) {
1195       continue;
1196     }
1197 
1198     /* 繋がっている入力ポートの先の Fx を訪問する
1199 入力ポートが無ければ終了 */
1200     int portCount = vptr->getInputPortCount();
1201     if (portCount < 1) {
1202       Sources.insert(vptr);
1203       continue;
1204     }
1205     for (int i = 0; i < portCount; i++) {
1206       TFxPort *port = vptr->getInputPort(i);
1207       if (!port) {
1208         continue;
1209       }
1210       TFxP u          = port->getFx();
1211       const TFx *uptr = u.getPointer();
1212       if (E.count(uptr) == 0) {
1213         E[uptr] = std::set<const TFx *>();
1214       }
1215       if (E[uptr].count(vptr) == 0) {
1216         E[uptr].insert(vptr);
1217       }
1218       Q.push(uptr);
1219     }
1220   }
1221 
1222   /* トポロジカルソート */
1223   std::set<const TFx *> visited;
1224   std::vector<const TFx *> L;
1225   std::function<void(const TFx *)> visit = [&visit, &visited, &E,
1226                                             &L](const TFx *fx) {
1227     if (visited.count(fx)) return;
1228     visited.insert(fx);
1229     auto edge = E[fx];
1230     for (auto i = edge.cbegin(); i != edge.cend(); i++) {
1231       visit(*i);
1232     }
1233     L.insert(L.begin(), fx);
1234   };
1235   for (auto i = E.cbegin(); i != E.cend(); i++) {
1236     visit(i->first);
1237   }
1238   return L;
1239 }
1240 
1241 //---------------------------------------------------------
1242 
startRendering(unsigned long renderId,const std::vector<TRenderer::RenderData> & renderDatas)1243 void TRendererImp::startRendering(
1244     unsigned long renderId,
1245     const std::vector<TRenderer::RenderData> &renderDatas) {
1246   rootFx = renderDatas.front().m_fxRoot.m_frameA;
1247   int T  = renderDatas.size();
1248   for (int z = 0; z < T; z++) {
1249     auto sortedFxs = calculateSortedFxs(renderDatas[z].m_fxRoot.m_frameA);
1250     if (z == 0) {
1251       for (auto fx : sortedFxs) {
1252         if (fx) const_cast<TFx *>(fx)->callStartRenderHandler();
1253       }
1254     }
1255   }
1256 
1257   struct locals {
1258     static inline void setStorage(TRendererImp *imp, unsigned long renderId) {
1259       rendererStorage.setLocalData(new (TRendererImp *)(imp));
1260       renderIdsStorage.setLocalData(new unsigned long(renderId));
1261     }
1262 
1263     static inline void clearStorage() {
1264       rendererStorage.setLocalData(0);
1265       renderIdsStorage.setLocalData(0);
1266     }
1267 
1268     static inline void declareStatusStart(TRendererImp *imp,
1269                                           TRenderer::RenderStatus status,
1270                                           RenderInstanceInfos *renderInfos) {
1271       renderInfos->m_status = status;
1272       imp->declareStatusStart(status);
1273     }
1274 
1275     //-----------------------------------------------------------------------
1276 
1277     struct InstanceDeclaration {
1278       TRendererImp *m_imp;
1279       unsigned long m_renderId;
1280       bool m_rollback;
1281 
1282       InstanceDeclaration(TRendererImp *imp, unsigned long renderId)
1283           : m_imp(imp), m_renderId(renderId), m_rollback(true) {}
1284 
1285       ~InstanceDeclaration() {
1286         if (m_rollback) {
1287           QMutexLocker locker(&m_imp->m_renderInstancesMutex);
1288 
1289           m_imp->m_activeInstances.erase(m_renderId);
1290           if (m_imp->m_undoneTasks == 0) m_imp->quitWaitingLoops();
1291         }
1292       }
1293 
1294       void commit() { m_rollback = false; }
1295     };
1296 
1297     struct StorageDeclaration {
1298       StorageDeclaration(TRendererImp *imp, unsigned long renderId) {
1299         setStorage(imp, renderId);
1300       }
1301 
1302       ~StorageDeclaration() { clearStorage(); }
1303     };
1304 
1305     struct RenderDeclaration {
1306       TRendererImp *m_imp;
1307       unsigned long m_renderId;
1308       bool m_rollback;
1309 
1310       RenderDeclaration(TRendererImp *imp, unsigned long renderId)
1311           : m_imp(imp), m_renderId(renderId), m_rollback(true) {
1312         imp->declareRenderStart(renderId);
1313       }
1314 
1315       ~RenderDeclaration() {
1316         if (m_rollback) m_imp->declareRenderEnd(m_renderId);
1317       }
1318 
1319       void commit() { m_rollback = false; }
1320     };
1321 
1322     struct StatusDeclaration {
1323       TRendererImp *m_imp;
1324       TRenderer::RenderStatus m_status;
1325 
1326       StatusDeclaration(TRendererImp *imp, TRenderer::RenderStatus status,
1327                         RenderInstanceInfos *renderInfos)
1328           : m_imp(imp), m_status(status) {
1329         declareStatusStart(imp, status, renderInfos);
1330       }
1331 
1332       ~StatusDeclaration() { m_imp->declareStatusEnd(m_status); }
1333     };
1334   };  // locals
1335 
1336   // DIAGNOSTICS_CLEAR;
1337 
1338   //----------------------------------------------------------------------
1339   //    Preliminary initializations
1340   //----------------------------------------------------------------------
1341 
1342   // Calculate the overall render area - sum of all render ports' areas
1343   TRectD renderArea;
1344   {
1345     QReadLocker sl(&m_portsLock);
1346 
1347     for (PortContainerIterator it = m_ports.begin(); it != m_ports.end(); ++it)
1348       renderArea += (*it)->getRenderArea();
1349   }
1350 
1351   const TRenderSettings &info(renderDatas[0].m_info);
1352 
1353   // Extract the render geometry
1354   TPointD pos(renderArea.getP00());
1355   TDimension frameSize(tceil(renderArea.getLx()), tceil(renderArea.getLy()));
1356 
1357   TRectD camBox(TPointD(pos.x / info.m_shrinkX, pos.y / info.m_shrinkY),
1358                 TDimensionD(frameSize.lx, frameSize.ly));
1359 
1360   // Refresh the raster pool specs
1361   m_rasterPool.setRasterSpecs(frameSize, info.m_bpp);
1362 
1363   // Set a temporary active instance count - so that hasToDie(renderId) returns
1364   // false
1365   RenderInstanceInfos *renderInfos;
1366   {
1367     QMutexLocker locker(&m_renderInstancesMutex);
1368     renderInfos                = &m_activeInstances[renderId];
1369     renderInfos->m_activeTasks = 1;
1370   }
1371 
1372   locals::InstanceDeclaration instanceDecl(this, renderId);
1373 
1374   //----------------------------------------------------------------------
1375   //    Clustering - Render Tasks creation
1376   //----------------------------------------------------------------------
1377 
1378   std::vector<RenderTask *> tasksVector;
1379 
1380   struct TasksCleaner {
1381     std::vector<RenderTask *> &m_tasksVector;
1382     ~TasksCleaner() {
1383       std::for_each(m_tasksVector.begin(), m_tasksVector.end(),
1384                     std::default_delete<RenderTask>());
1385     }
1386   } tasksCleaner = {tasksVector};
1387 
1388   unsigned long tasksIdCounter = 0;
1389 
1390   std::map<std::string, RenderTask *> clusters;
1391   std::vector<TRenderer::RenderData>::const_iterator it;
1392   std::map<std::string, RenderTask *>::iterator jt;
1393 
1394   for (it = renderDatas.begin(); it != renderDatas.end(); ++it) {
1395     // Check for user cancels
1396     if (hasToDie(renderId)) return;
1397 
1398     // Build the frame's description alias
1399     const TRenderer::RenderData &renderData = *it;
1400 
1401     /*--- カメラサイズ (LevelAutoやノイズで使用する) ---*/
1402     TRenderSettings rs = renderData.m_info;
1403     rs.m_cameraBox     = camBox;
1404     /*--- 途中でPreview計算がキャンセルされたときのフラグ ---*/
1405     rs.m_isCanceled = &renderInfos->m_canceled;
1406 
1407     TRasterFxP fx = renderData.m_fxRoot.m_frameA;
1408     assert(fx);
1409 
1410     double frame = renderData.m_frame;
1411 
1412     std::string alias = fx->getAlias(frame, renderData.m_info);
1413     if (renderData.m_fxRoot.m_frameB)
1414       alias = alias +
1415               renderData.m_fxRoot.m_frameB->getAlias(frame, renderData.m_info);
1416 
1417     // If the render contains offscreen render, then prepare the
1418     // QOffscreenSurface
1419     // in main (GUI) thread. For now it is used only in the plasticDeformerFx.
1420     if (alias.find("plasticDeformerFx") != std::string::npos &&
1421         QThread::currentThread() == qGuiApp->thread()) {
1422       rs.m_offScreenSurface.reset(new QOffscreenSurface());
1423       rs.m_offScreenSurface->setFormat(QSurfaceFormat::defaultFormat());
1424       rs.m_offScreenSurface->create();
1425     }
1426 
1427     // Search the alias among stored clusters - and store the frame
1428     jt = clusters.find(alias);
1429 
1430     if (jt == clusters.end()) {
1431       RenderTask *newTask =
1432           new RenderTask(renderId, tasksIdCounter++, renderData.m_frame, rs,
1433                          renderData.m_fxRoot, pos, frameSize, this);
1434 
1435       tasksVector.push_back(newTask);
1436       clusters.insert(std::make_pair(alias, newTask));
1437     } else
1438       jt->second->addFrame(renderData.m_frame);
1439 
1440     // Call processEvents to make the GUI reactive.
1441     QCoreApplication::instance()->processEvents();
1442   }
1443 
1444   // Release the clusters - we'll just need the tasks vector from now on
1445   clusters.clear();
1446 
1447   std::vector<RenderTask *>::iterator kt, kEnd = tasksVector.end();
1448   {
1449     // Install TRenderer on current thread before proceeding
1450     locals::StorageDeclaration storageDecl(this, renderId);
1451 
1452     // Inform the resource managers
1453     locals::RenderDeclaration renderDecl(this, renderId);
1454 
1455     //----------------------------------------------------------------------
1456     //    Precomputing
1457     //----------------------------------------------------------------------
1458 
1459     if (m_precomputingEnabled) {
1460       // Set current maxTileSize for cache manager precomputation
1461       const TRenderSettings &rs = renderDatas[0].m_info;
1462       TPredictiveCacheManager::instance()->setMaxTileSize(rs.m_maxTileSize);
1463       TPredictiveCacheManager::instance()->setBPP(rs.m_bpp);
1464 
1465       // Perform the first precomputing run - fx usages declaration
1466       {
1467         locals::StatusDeclaration firstrunDecl(this, TRenderer::FIRSTRUN,
1468                                                renderInfos);
1469 
1470         for (kt = tasksVector.begin(); kt != kEnd; ++kt) {
1471           if (hasToDie(renderId)) return;
1472 
1473           (*kt)->preRun();
1474 
1475           // NOTE: Thread-specific data must be temporarily uninstalled before
1476           // processing events (which may redefine the thread data).
1477           locals::clearStorage();
1478           QCoreApplication::instance()->processEvents();
1479           locals::setStorage(this, renderId);
1480         }
1481       }
1482 
1483       // Pass to the TESTRUN status - this one should faithfully reproduce
1484       // the actual COMPUTING status
1485       {
1486         locals::StatusDeclaration testrunDecl(this, TRenderer::TESTRUN,
1487                                               renderInfos);
1488 
1489         for (kt = tasksVector.begin(); kt != kEnd; ++kt) {
1490           if (hasToDie(renderId)) return;
1491 
1492           (*kt)->preRun();
1493 
1494           // NOTE: Thread-specific data must be temporarily uninstalled before
1495           // processing events (which may redefine the thread data).
1496           locals::clearStorage();
1497           QCoreApplication::instance()->processEvents();
1498           locals::setStorage(this, renderId);
1499         }
1500       }
1501     }
1502 
1503     //----------------------------------------------------------------------
1504     //    Render
1505     //----------------------------------------------------------------------
1506 
1507     locals::declareStatusStart(this, TRenderer::COMPUTING, renderInfos);
1508 
1509     // Update the tasks counts
1510     m_undoneTasks += tasksVector.size();
1511     {
1512       QMutexLocker locker(&m_renderInstancesMutex);
1513       renderInfos->m_activeTasks = tasksVector.size();
1514     }
1515 
1516     renderDecl.commit();  // Declarations are taken over by render tasks
1517   }
1518 
1519   instanceDecl.commit();  // Same here
1520 
1521   // Launch the render
1522   for (kt = tasksVector.begin(); kt != tasksVector.end(); ++kt)
1523     m_executor.addTask(*kt);
1524 
1525   tasksVector.clear();  // Prevent tasks destruction by TasksCleaner
1526 }
1527 
initialize()1528 void TRenderer::initialize() { TRendererStartInvoker::instance(); }
1529