Fraxinus  16.5.0-fx-rc1
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 #include "cxRenderLoop.h"
33 
34 #include "cxCyclicActionLogger.h"
35 #include <QTimer>
36 #include "cxView.h"
37 #include "vtkRenderWindow.h"
38 #include "cxTypeConversions.h"
39 #include "cxLogger.h"
40 #include "cxViewCollectionWidget.h"
41 
42 
43 namespace cx
44 {
45 
47  QObject(NULL),
48  mTimer(NULL),
49  mPreRenderSignalRequested(false),
50  mSmartRender(false),
51  mLogging(false),
52  mBaseRenderInterval(40)
53 {
54  mLastFullRender = QDateTime::currentDateTime();
55  mCyclicLogger.reset(new CyclicActionLogger("Main Render timer"));
56 
57  mTimer = new QTimer(this);
58  connect(mTimer, SIGNAL(timeout()), this, SLOT(timeoutSlot()));
59 
60  this->sendRenderIntervalToTimer(mBaseRenderInterval);
61 }
62 
64 {
65  mTimer->start();
66 }
67 
69 {
70  mTimer->stop();
71  emit fps(0);
72 }
73 
75 {
76  return mTimer->isActive();
77 }
78 
80 {
81  mPreRenderSignalRequested = true;
82 }
83 
85 {
86  mBaseRenderInterval = interval;
87  this->sendRenderIntervalToTimer(mBaseRenderInterval);
88 }
89 
91 {
92  mLogging = on;
93 }
94 
96 {
97  mSmartRender = val;
98 }
99 
100 void RenderLoop::sendRenderIntervalToTimer(int interval)
101 {
102  if (interval==mTimer->interval())
103  return;
104  if (interval == 0)
105  interval = 30;
106 
107  bool active = this->isRunning();
108  if (active)
109  mTimer->stop();
110  mTimer->setInterval(interval);
111  if (active)
112  mTimer->start();
113 }
114 
116 {
117  mLayoutWidgets.push_back(layout);
118 }
119 
120 
122 {
123  mLayoutWidgets.clear();
124 }
125 
126 void RenderLoop::timeoutSlot()
127 {
128  mCyclicLogger->begin();
129  mLastBeginRender = QDateTime::currentDateTime();
130  this->sendRenderIntervalToTimer(mBaseRenderInterval);
131 
132  this->emitPreRenderIfRequested();
133 
134  this->renderViews();
135 
136  this->emitFPSIfRequired();
137 
138  int timeToNext = this->calculateTimeToNextRender();
139  this->sendRenderIntervalToTimer(timeToNext);
140 }
141 
142 void RenderLoop::emitPreRenderIfRequested()
143 {
144  if(mPreRenderSignalRequested)
145  {
146  emit preRender();
147  mPreRenderSignalRequested = false;
148  }
149  // mRenderTimer->time("prerender");
150 }
151 
152 void RenderLoop::renderViews()
153 {
154  bool smart = this->pollForSmartRenderingThisCycle();
155 
156  for (unsigned i=0; i<mLayoutWidgets.size(); ++i)
157  {
158  if (mLayoutWidgets[i])
159  {
160  if (!smart)
161  mLayoutWidgets[i]->setModified();
162  mLayoutWidgets[i]->render();
163  }
164  }
165 
166  mCyclicLogger->time("render");
167  emit renderFinished();
168 }
169 
170 bool RenderLoop::pollForSmartRenderingThisCycle()
171 {
172  // do a full render anyway at low rate. This is a convenience hack for rendering
173  // occational effects that the smart render is too dumb to see.
174  bool smart = mSmartRender;
175  int smartInterval = mTimer->interval() * 40;
176  int passed = mLastFullRender.time().msecsTo(QDateTime::currentDateTime().time());
177 
178  if (passed > smartInterval)
179  smart = false;
180  if (!smart)
181  mLastFullRender = QDateTime::currentDateTime();
182  return smart;
183 }
184 
185 void RenderLoop::emitFPSIfRequired()
186 {
187  if (mCyclicLogger->intervalPassed())
188  {
189  emit fps(mCyclicLogger->getFPS());
190  this->dumpStatistics();
191 // static int counter=0;
192 // if (++counter%3==0)
193 // reportDebug(mCyclicLogger->dumpStatisticsSmall());
194  mCyclicLogger->reset();
195  }
196 }
197 
198 void RenderLoop::dumpStatistics()
199 {
200  if (!mLogging)
201  return;
202 
203  static int counter=0;
204  if (++counter%3==0) // every third event
205  reportDebug(mCyclicLogger->dumpStatisticsSmall());
206 }
207 
208 int RenderLoop::calculateTimeToNextRender()
209 {
210  // tests show that the application wait between renderings even if the rendering uses more time
211  // than the interval. This hack shortens the wait time between renderings but keeps below the
212  // input update rate at all times.
213  int usage = mLastBeginRender.msecsTo(QDateTime::currentDateTime()); // time spent in rendering
214  int leftover = std::max(0, mTimer->interval() - usage); // time left of the rendering interval
215  int timeToNext = std::max(1, leftover); // always wait at least 1ms - give others time to do stuff
216  // std::cout << QString("setting interval %1, usage is %2").arg(timeToNext).arg(usage) << std::endl;
217  return timeToNext;
218 }
219 
220 } // namespace cx
221 
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 requestPreRenderSignal()
void reportDebug(QString msg)
Definition: cxLogger.cpp:89