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