CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxRenderLoop.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 #include "cxRenderLoop.h"
12 
13 #include "cxCyclicActionLogger.h"
14 #include <QTimer>
15 #include "cxView.h"
16 #include "vtkRenderWindow.h"
17 #include "cxTypeConversions.h"
18 #include "cxLogger.h"
19 #include "cxViewCollectionWidget.h"
20 
21 
22 namespace cx
23 {
24 
26  QObject(NULL),
27  mTimer(NULL),
28  mSmartRender(false),
29  mLogging(false),
30  mBaseRenderInterval(40)
31 {
32  mLastFullRender = QDateTime::currentDateTime();
33  mCyclicLogger.reset(new CyclicActionLogger("Main Render timer"));
34 
35  mTimer = new QTimer(this);
36  connect(mTimer, SIGNAL(timeout()), this, SLOT(timeoutSlot()));
37 
38  this->sendRenderIntervalToTimer(mBaseRenderInterval);
39 }
40 
42 {
43  mTimer->start();
44 }
45 
47 {
48  mTimer->stop();
49  emit fps(0);
50 }
51 
53 {
54  return mTimer->isActive();
55 }
56 
58 {
59  mBaseRenderInterval = interval;
60  this->sendRenderIntervalToTimer(mBaseRenderInterval);
61 }
62 
64 {
65  mLogging = on;
66 }
67 
69 {
70  mSmartRender = val;
71 }
72 
73 void RenderLoop::sendRenderIntervalToTimer(int interval)
74 {
75  if (interval==mTimer->interval())
76  return;
77  if (interval == 0)
78  interval = 30;
79 
80  bool active = this->isRunning();
81  if (active)
82  mTimer->stop();
83  mTimer->setInterval(interval);
84  if (active)
85  mTimer->start();
86 }
87 
89 {
90  mLayoutWidgets.push_back(layout);
91 }
92 
93 
95 {
96  mLayoutWidgets.clear();
97 }
98 
99 void RenderLoop::timeoutSlot()
100 {
101  mCyclicLogger->begin();
102  mLastBeginRender = QDateTime::currentDateTime();
103  this->sendRenderIntervalToTimer(mBaseRenderInterval);
104 
105  emit preRender();
106 
107  this->renderViews();
108 
109  this->emitFPSIfRequired();
110 
111  int timeToNext = this->calculateTimeToNextRender();
112  this->sendRenderIntervalToTimer(timeToNext);
113 }
114 
115 void RenderLoop::renderViews()
116 {
117  bool smart = this->pollForSmartRenderingThisCycle();
118 
119  for (unsigned i=0; i<mLayoutWidgets.size(); ++i)
120  {
121  if (mLayoutWidgets[i])
122  {
123  if (!smart)
124  mLayoutWidgets[i]->setModified();
125  mLayoutWidgets[i]->render();
126  }
127  }
128 
129  mCyclicLogger->time("render");
130  emit renderFinished();
131 }
132 
133 bool RenderLoop::pollForSmartRenderingThisCycle()
134 {
135  // do a full render anyway at low rate. This is a convenience hack for rendering
136  // occational effects that the smart render is too dumb to see.
137  bool smart = mSmartRender;
138  int smartInterval = mTimer->interval() * 40;
139  int passed = mLastFullRender.time().msecsTo(QDateTime::currentDateTime().time());
140 
141  if (passed > smartInterval)
142  smart = false;
143  if (!smart)
144  mLastFullRender = QDateTime::currentDateTime();
145  return smart;
146 }
147 
148 void RenderLoop::emitFPSIfRequired()
149 {
150  if (mCyclicLogger->intervalPassed())
151  {
152  emit fps(mCyclicLogger->getFPS());
153  this->dumpStatistics();
154 // static int counter=0;
155 // if (++counter%3==0)
156 // reportDebug(mCyclicLogger->dumpStatisticsSmall());
157  mCyclicLogger->reset();
158  }
159 }
160 
161 void RenderLoop::dumpStatistics()
162 {
163  if (!mLogging)
164  return;
165 
166  static int counter=0;
167  if (++counter%3==0) // every third event
168  reportDebug(mCyclicLogger->dumpStatisticsSmall());
169 }
170 
171 int RenderLoop::calculateTimeToNextRender()
172 {
173  // tests show that the application wait between renderings even if the rendering uses more time
174  // than the interval. This hack shortens the wait time between renderings but keeps below the
175  // input update rate at all times.
176  int usage = mLastBeginRender.msecsTo(QDateTime::currentDateTime()); // time spent in rendering
177  int leftover = std::max(0, mTimer->interval() - usage); // time left of the rendering interval
178  int timeToNext = std::max(1, leftover); // always wait at least 1ms - give others time to do stuff
179  // std::cout << QString("setting interval %1, usage is %2").arg(timeToNext).arg(usage) << std::endl;
180  return timeToNext;
181 }
182 
183 } // namespace cx
184 
void renderFinished()
void setRenderingInterval(int interval)
void fps(int number)
Emits number of frames per second.
bool isRunning() const
void addLayout(ViewCollectionWidget *layout)
void setLogging(bool on)
void setSmartRender(bool val)
If set: Render only views with modified props using the given interval, render nonmodified at a slowe...
void reportDebug(QString msg)
Definition: cxLogger.cpp:68
Namespace for all CustusX production code.