1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkOpenGLRenderTimer.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15
16 #include "vtkOpenGLRenderTimer.h"
17
18 #include "vtkObjectFactory.h"
19 #include "vtkOpenGLRenderer.h" // For query allocation bug check
20
21 #include "vtk_glew.h"
22
23 // glQueryCounter unavailable in OpenGL ES:
24 #if defined(GL_ES_VERSION_3_0)
25 #define NO_TIMESTAMP_QUERIES
26 #endif
27
28 //------------------------------------------------------------------------------
vtkOpenGLRenderTimer()29 vtkOpenGLRenderTimer::vtkOpenGLRenderTimer()
30 : StartReady(false),
31 EndReady(false),
32 StartQuery(0),
33 EndQuery(0),
34 StartTime(0),
35 EndTime(0),
36 ReusableStarted(false),
37 ReusableEnded(false)
38 {
39 }
40
41 //------------------------------------------------------------------------------
~vtkOpenGLRenderTimer()42 vtkOpenGLRenderTimer::~vtkOpenGLRenderTimer()
43 {
44 if (this->StartQuery != 0 || this->EndQuery != 0)
45 {
46 this->Reset();
47 }
48 }
49
50 //------------------------------------------------------------------------------
IsSupported()51 bool vtkOpenGLRenderTimer::IsSupported()
52 {
53 #ifdef NO_TIMESTAMP_QUERIES
54 return false;
55 #else
56 static const bool s = !vtkOpenGLRenderer::HaveAppleQueryAllocationBug();
57 return s;
58 #endif
59 }
60
61 //------------------------------------------------------------------------------
Reset()62 void vtkOpenGLRenderTimer::Reset()
63 {
64 #ifndef NO_TIMESTAMP_QUERIES
65 if (!this->IsSupported())
66 {
67 return;
68 }
69
70 if (this->StartQuery != 0)
71 {
72 glDeleteQueries(1, static_cast<GLuint*>(&this->StartQuery));
73 this->StartQuery = 0;
74 }
75
76 if (this->EndQuery != 0)
77 {
78 glDeleteQueries(1, static_cast<GLuint*>(&this->EndQuery));
79 this->EndQuery = 0;
80 }
81
82 this->StartReady = false;
83 this->EndReady = false;
84 this->StartTime = 0;
85 this->EndTime = 0;
86 #endif // NO_TIMESTAMP_QUERIES
87 }
88
89 //------------------------------------------------------------------------------
Start()90 void vtkOpenGLRenderTimer::Start()
91 {
92 if (!this->IsSupported())
93 {
94 return;
95 }
96
97 this->Reset();
98
99 #ifndef NO_TIMESTAMP_QUERIES
100 glGenQueries(1, static_cast<GLuint*>(&this->StartQuery));
101 glQueryCounter(static_cast<GLuint>(this->StartQuery), GL_TIMESTAMP);
102 #endif // NO_TIMESTAMP_QUERIES
103 }
104
105 //------------------------------------------------------------------------------
Stop()106 void vtkOpenGLRenderTimer::Stop()
107 {
108 #ifndef NO_TIMESTAMP_QUERIES
109 if (!this->IsSupported())
110 {
111 return;
112 }
113
114 if (this->EndQuery != 0)
115 {
116 vtkGenericWarningMacro("vtkOpenGLRenderTimer::Stop called before "
117 "resetting. Ignoring.");
118 return;
119 }
120
121 if (this->StartQuery == 0)
122 {
123 vtkGenericWarningMacro("vtkOpenGLRenderTimer::Stop called before "
124 "vtkOpenGLRenderTimer::Start. Ignoring.");
125 return;
126 }
127
128 glGenQueries(1, static_cast<GLuint*>(&this->EndQuery));
129 glQueryCounter(static_cast<GLuint>(this->EndQuery), GL_TIMESTAMP);
130 #endif // NO_TIMESTAMP_QUERIES
131 }
132
133 //------------------------------------------------------------------------------
Started()134 bool vtkOpenGLRenderTimer::Started()
135 {
136 #ifndef NO_TIMESTAMP_QUERIES
137 return this->StartQuery != 0;
138 #else // NO_TIMESTAMP_QUERIES
139 return false;
140 #endif // NO_TIMESTAMP_QUERIES
141 }
142
143 //------------------------------------------------------------------------------
Stopped()144 bool vtkOpenGLRenderTimer::Stopped()
145 {
146 #ifndef NO_TIMESTAMP_QUERIES
147 return this->EndQuery != 0;
148 #else // NO_TIMESTAMP_QUERIES
149 return false;
150 #endif // NO_TIMESTAMP_QUERIES
151 }
152
153 //------------------------------------------------------------------------------
Ready()154 bool vtkOpenGLRenderTimer::Ready()
155 {
156 #ifndef NO_TIMESTAMP_QUERIES
157 if (!this->IsSupported())
158 {
159 return false;
160 }
161
162 if (!this->StartReady)
163 {
164 GLint ready;
165 glGetQueryObjectiv(static_cast<GLuint>(this->StartQuery),
166 GL_QUERY_RESULT_AVAILABLE, &ready);
167 if (!ready)
168 {
169 return false;
170 }
171
172 this->StartReady = true;
173 glGetQueryObjectui64v(static_cast<GLuint>(this->StartQuery),
174 GL_QUERY_RESULT,
175 reinterpret_cast<GLuint64*>(&this->StartTime));
176 }
177
178 if (!this->EndReady)
179 {
180 GLint ready;
181 glGetQueryObjectiv(static_cast<GLuint>(this->EndQuery),
182 GL_QUERY_RESULT_AVAILABLE, &ready);
183 if (!ready)
184 {
185 return false;
186 }
187
188 this->EndReady = true;
189 glGetQueryObjectui64v(static_cast<GLuint>(this->EndQuery),
190 GL_QUERY_RESULT,
191 reinterpret_cast<GLuint64*>(&this->EndTime));
192 }
193 #endif // NO_TIMESTAMP_QUERIES
194
195 return true;
196 }
197
198 //------------------------------------------------------------------------------
GetElapsedSeconds()199 float vtkOpenGLRenderTimer::GetElapsedSeconds()
200 {
201 #ifndef NO_TIMESTAMP_QUERIES
202 if (!this->Ready())
203 {
204 return 0.f;
205 }
206
207 return (this->EndTime - this->StartTime) * 1e-9f;
208 #else // NO_TIMESTAMP_QUERIES
209 return 0.f;
210 #endif // NO_TIMESTAMP_QUERIES
211 }
212
213 //------------------------------------------------------------------------------
GetElapsedMilliseconds()214 float vtkOpenGLRenderTimer::GetElapsedMilliseconds()
215 {
216 #ifndef NO_TIMESTAMP_QUERIES
217 if (!this->Ready())
218 {
219 return 0.f;
220 }
221
222 return (this->EndTime - this->StartTime) * 1e-6f;
223 #else // NO_TIMESTAMP_QUERIES
224 return 0.f;
225 #endif // NO_TIMESTAMP_QUERIES
226 }
227
228 //------------------------------------------------------------------------------
229 vtkTypeUInt64
GetElapsedNanoseconds()230 vtkOpenGLRenderTimer::GetElapsedNanoseconds()
231 {
232 #ifndef NO_TIMESTAMP_QUERIES
233 if (!this->Ready())
234 {
235 return 0;
236 }
237
238 return (this->EndTime - this->StartTime);
239 #else // NO_TIMESTAMP_QUERIES
240 return 0;
241 #endif // NO_TIMESTAMP_QUERIES
242 }
243
244 //------------------------------------------------------------------------------
GetStartTime()245 vtkTypeUInt64 vtkOpenGLRenderTimer::GetStartTime()
246 {
247 #ifndef NO_TIMESTAMP_QUERIES
248 if (!this->Ready())
249 {
250 return 0;
251 }
252
253 return this->StartTime;
254 #else // NO_TIMESTAMP_QUERIES
255 return 0;
256 #endif // NO_TIMESTAMP_QUERIES
257 }
258
259 //------------------------------------------------------------------------------
GetStopTime()260 vtkTypeUInt64 vtkOpenGLRenderTimer::GetStopTime()
261 {
262 #ifndef NO_TIMESTAMP_QUERIES
263 if (!this->Ready())
264 {
265 return 0;
266 }
267
268 return this->EndTime;
269 #else // NO_TIMESTAMP_QUERIES
270 return 0;
271 #endif // NO_TIMESTAMP_QUERIES
272 }
273
274 //------------------------------------------------------------------------------
ReleaseGraphicsResources()275 void vtkOpenGLRenderTimer::ReleaseGraphicsResources()
276 {
277 this->Reset();
278 }
279
280 //------------------------------------------------------------------------------
ReusableStart()281 void vtkOpenGLRenderTimer::ReusableStart()
282 {
283 #ifndef NO_TIMESTAMP_QUERIES
284 if (!this->IsSupported())
285 {
286 return;
287 }
288
289 if (this->StartQuery == 0)
290 {
291 glGenQueries(1, static_cast<GLuint*>(&this->StartQuery));
292 glQueryCounter(static_cast<GLuint>(this->StartQuery), GL_TIMESTAMP);
293 this->ReusableStarted = true;
294 this->ReusableEnded = false;
295 }
296 if (!this->ReusableStarted)
297 {
298 glQueryCounter(static_cast<GLuint>(this->StartQuery), GL_TIMESTAMP);
299 this->ReusableStarted = true;
300 this->ReusableEnded = false;
301 }
302 #endif // NO_TIMESTAMP_QUERIES
303 }
304
305 //------------------------------------------------------------------------------
ReusableStop()306 void vtkOpenGLRenderTimer::ReusableStop()
307 {
308 #ifndef NO_TIMESTAMP_QUERIES
309 if (!this->IsSupported())
310 {
311 return;
312 }
313
314 if (!this->ReusableStarted)
315 {
316 vtkGenericWarningMacro("vtkOpenGLRenderTimer::ReusableStop called before "
317 "vtkOpenGLRenderTimer::ReusableStart. Ignoring.");
318 return;
319 }
320
321 if (this->EndQuery == 0)
322 {
323 glGenQueries(1, static_cast<GLuint*>(&this->EndQuery));
324 glQueryCounter(static_cast<GLuint>(this->EndQuery), GL_TIMESTAMP);
325 this->ReusableEnded = true;
326 }
327 if (!this->ReusableEnded)
328 {
329 glQueryCounter(static_cast<GLuint>(this->EndQuery), GL_TIMESTAMP);
330 this->ReusableEnded = true;
331 }
332 #endif // NO_TIMESTAMP_QUERIES
333 }
334
335 //------------------------------------------------------------------------------
GetReusableElapsedSeconds()336 float vtkOpenGLRenderTimer::GetReusableElapsedSeconds()
337 {
338 #ifndef NO_TIMESTAMP_QUERIES
339 // we do not have an end query yet so we cannot have a time
340 if (!this->EndQuery)
341 {
342 return 0.0;
343 }
344
345 if (this->ReusableStarted && !this->StartReady)
346 {
347 GLint ready;
348 glGetQueryObjectiv(static_cast<GLuint>(this->StartQuery),
349 GL_QUERY_RESULT_AVAILABLE, &ready);
350 if (ready)
351 {
352 this->StartReady = true;
353 }
354 }
355
356 if (this->StartReady && this->ReusableEnded && !this->EndReady)
357 {
358 GLint ready;
359 glGetQueryObjectiv(static_cast<GLuint>(this->EndQuery),
360 GL_QUERY_RESULT_AVAILABLE, &ready);
361 if (ready)
362 {
363 this->EndReady = true;
364 }
365 }
366
367 // if everything is ready read the times to get a new elapsed time
368 // and then prep for a new flight. This also has the benefit that
369 // if no one is getting the elapsed time then nothing is done
370 // beyond the first flight.
371 if (this->StartReady && this->EndReady)
372 {
373 glGetQueryObjectui64v(static_cast<GLuint>(this->StartQuery),
374 GL_QUERY_RESULT,
375 reinterpret_cast<GLuint64*>(&this->StartTime));
376 glGetQueryObjectui64v(static_cast<GLuint>(this->EndQuery),
377 GL_QUERY_RESULT,
378 reinterpret_cast<GLuint64*>(&this->EndTime));
379 // it was ready so prepare another flight
380 this->ReusableStarted = false;
381 this->ReusableEnded = false;
382 this->StartReady = false;
383 this->EndReady = false;
384 }
385
386 return (this->EndTime - this->StartTime) * 1e-9f;
387 #else // NO_TIMESTAMP_QUERIES
388 return 0.f;
389 #endif // NO_TIMESTAMP_QUERIES
390 }
391