5e30547b |
1 | // Copyright (c) 2017 OPEN CASCADE SAS |
2 | // |
3 | // This file is part of Open CASCADE Technology software library. |
4 | // |
5 | // This library is free software; you can redistribute it and/or modify it under |
6 | // the terms of the GNU Lesser General Public License version 2.1 as published |
7 | // by the Free Software Foundation, with special exception defined in the file |
8 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
9 | // distribution for complete text of the license and disclaimer of any warranty. |
10 | // |
11 | // Alternatively, this file may be used under the terms of Open CASCADE |
12 | // commercial license or contractual agreement. |
13 | |
14 | #include <Graphic3d_FrameStats.hxx> |
15 | |
16 | #include <Graphic3d_CView.hxx> |
17 | |
18 | IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_FrameStats, Standard_Transient) |
19 | |
20 | namespace |
21 | { |
22 | //! Format counter. |
23 | static std::ostream& formatCounter (std::ostream& theStream, |
24 | Standard_Integer theWidth, |
25 | const char* thePrefix, |
26 | Standard_Size theValue, |
27 | const char* thePostfix = NULL) |
28 | { |
29 | if (thePrefix != NULL) |
30 | { |
31 | theStream << thePrefix; |
32 | } |
33 | theStream << std::setfill(' ') << std::setw (theWidth); |
34 | if (theValue >= 1000000000) |
35 | { |
36 | Standard_Real aValM = Standard_Real(theValue) / 1000000000.0; |
37 | theStream << std::fixed << std::setprecision (1) << aValM << "G"; |
38 | } |
39 | else if (theValue >= 1000000) |
40 | { |
41 | Standard_Real aValM = Standard_Real(theValue) / 1000000.0; |
42 | theStream << std::fixed << std::setprecision (1) << aValM << "M"; |
43 | } |
44 | else if (theValue >= 1000) |
45 | { |
46 | Standard_Real aValK = Standard_Real(theValue) / 1000.0; |
47 | theStream << std::fixed << std::setprecision (1) << aValK << "k"; |
48 | } |
49 | else |
50 | { |
51 | theStream << theValue; |
8f5760bc |
52 | if (thePostfix == NULL) |
53 | { |
54 | theStream << " "; |
55 | } |
5e30547b |
56 | } |
57 | if (thePostfix != NULL) |
58 | { |
59 | theStream << thePostfix; |
60 | } |
61 | return theStream; |
62 | } |
63 | |
8f5760bc |
64 | //! Format a pair of counters. |
65 | static std::ostream& formatCounterPair (std::ostream& theStream, |
66 | Standard_Integer theWidth, |
67 | const char* thePrefix, |
68 | Standard_Size theValue, |
69 | Standard_Size theImmValue, |
70 | bool theToShowImmediate) |
71 | { |
72 | formatCounter (theStream, theWidth, thePrefix, theValue, NULL); |
73 | if (theToShowImmediate) |
74 | { |
75 | formatCounter (theStream, 1, "(", theImmValue, ")"); |
76 | } |
77 | theStream << "\n"; |
78 | return theStream; |
79 | } |
80 | |
5e30547b |
81 | //! Format memory counter. |
82 | static std::ostream& formatBytes (std::ostream& theStream, |
83 | Standard_Integer theWidth, |
84 | const char* thePrefix, |
85 | Standard_Size theValue, |
86 | const char* thePostfix = NULL) |
87 | { |
88 | if (thePrefix != NULL) |
89 | { |
90 | theStream << thePrefix; |
91 | } |
92 | theStream << std::setfill(' ') << std::setw (theWidth); |
93 | if (theValue >= 1024 * 1024 * 1024) |
94 | { |
95 | Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0 * 1024.0); |
96 | theStream << std::fixed << std::setprecision (1) << aValM << " GiB"; |
97 | } |
98 | else if (theValue >= 1024 * 1024) |
99 | { |
100 | Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0); |
101 | theStream << std::fixed << std::setprecision (1) << aValM << " MiB"; |
102 | } |
103 | else if (theValue >= 1024) |
104 | { |
105 | Standard_Real aValK = Standard_Real(theValue) / 1024.0; |
106 | theStream << std::fixed << std::setprecision (1) << aValK << " KiB"; |
107 | } |
108 | else |
109 | { |
110 | theStream << theValue << " B"; |
111 | } |
112 | if (thePostfix != NULL) |
113 | { |
114 | theStream << thePostfix; |
115 | } |
116 | return theStream; |
117 | } |
118 | |
119 | static const Standard_Real THE_SECONDS_IN_HOUR = 3600.0; |
120 | static const Standard_Real THE_SECONDS_IN_MINUTE = 60.0; |
121 | static const Standard_Real THE_SECOND_IN_HOUR = 1.0 / THE_SECONDS_IN_HOUR; |
122 | static const Standard_Real THE_SECOND_IN_MINUTE = 1.0 / THE_SECONDS_IN_MINUTE; |
123 | |
124 | //! Format time. |
125 | static std::ostream& formatTime (std::ostream& theStream, |
126 | Standard_Integer theWidth, |
127 | const char* thePrefix, |
128 | Standard_Real theSeconds, |
129 | const char* thePostfix = NULL) |
130 | { |
131 | if (thePrefix != NULL) |
132 | { |
133 | theStream << thePrefix; |
134 | } |
135 | |
136 | Standard_Real aSecIn = theSeconds; |
137 | unsigned int aHours = (unsigned int )(aSecIn * THE_SECOND_IN_HOUR); |
138 | aSecIn -= Standard_Real(aHours) * THE_SECONDS_IN_HOUR; |
139 | unsigned int aMinutes = (unsigned int )(aSecIn * THE_SECOND_IN_MINUTE); |
140 | aSecIn -= Standard_Real(aMinutes) * THE_SECONDS_IN_MINUTE; |
141 | unsigned int aSeconds = (unsigned int )aSecIn; |
142 | aSecIn -= Standard_Real(aSeconds); |
143 | Standard_Real aMilliSeconds = 1000.0 * aSecIn; |
144 | |
145 | char aBuffer[64]; |
146 | theStream << std::setfill(' ') << std::setw (theWidth); |
147 | if (aHours > 0) |
148 | { |
149 | Sprintf (aBuffer, "%02u:%02u:%02u", aHours, aMinutes, aSeconds); |
150 | theStream << aBuffer; |
151 | } |
152 | else if (aMinutes > 0) |
153 | { |
154 | Sprintf (aBuffer, "%02u:%02u", aMinutes, aSeconds); |
155 | theStream << aBuffer; |
156 | } |
157 | else if (aSeconds > 0) |
158 | { |
159 | Sprintf (aBuffer, "%2u s", aSeconds); |
160 | theStream << aBuffer; |
161 | } |
162 | else |
163 | { |
164 | theStream << std::fixed << std::setprecision (1) << aMilliSeconds << " ms"; |
165 | } |
166 | |
167 | if (thePostfix != NULL) |
168 | { |
169 | theStream << thePostfix; |
170 | } |
171 | return theStream; |
172 | } |
79b544e6 |
173 | |
174 | //! Add key-value pair to the dictionary. |
175 | static void addInfo (TColStd_IndexedDataMapOfStringString& theDict, |
176 | const TCollection_AsciiString& theKey, |
177 | const char* theValue) |
178 | { |
179 | TCollection_AsciiString aValue (theValue != NULL ? theValue : ""); |
180 | theDict.ChangeFromIndex (theDict.Add (theKey, aValue)) = aValue; |
181 | } |
182 | |
183 | //! Add key-value pair to the dictionary. |
184 | static void addInfo (TColStd_IndexedDataMapOfStringString& theDict, |
185 | const TCollection_AsciiString& theKey, |
186 | const Standard_Real theValue) |
187 | { |
188 | char aTmp[50]; |
189 | Sprintf (aTmp, "%.1g", theValue); |
190 | addInfo (theDict, theKey, aTmp); |
191 | } |
192 | |
193 | //! Add key-value pair to the dictionary. |
194 | static void addInfo (TColStd_IndexedDataMapOfStringString& theDict, |
195 | const TCollection_AsciiString& theKey, |
196 | const Standard_Size theValue) |
197 | { |
198 | char aTmp[50]; |
199 | Sprintf (aTmp, "%zu", theValue); |
200 | addInfo (theDict, theKey, aTmp); |
201 | } |
202 | |
203 | //! Format time. |
204 | static void addTimeInfo (TColStd_IndexedDataMapOfStringString& theDict, |
205 | const TCollection_AsciiString& theKey, |
206 | Standard_Real theSeconds) |
207 | { |
208 | Standard_Real aSecIn = theSeconds; |
209 | unsigned int aHours = (unsigned int )(aSecIn * THE_SECOND_IN_HOUR); |
210 | aSecIn -= Standard_Real(aHours) * THE_SECONDS_IN_HOUR; |
211 | unsigned int aMinutes = (unsigned int )(aSecIn * THE_SECOND_IN_MINUTE); |
212 | aSecIn -= Standard_Real(aMinutes) * THE_SECONDS_IN_MINUTE; |
213 | unsigned int aSeconds = (unsigned int )aSecIn; |
214 | aSecIn -= Standard_Real(aSeconds); |
215 | Standard_Real aMilliSeconds = 1000.0 * aSecIn; |
216 | |
217 | char aBuffer[64]; |
218 | if (aHours > 0) |
219 | { |
220 | Sprintf (aBuffer, "%02u:%02u:%02u", aHours, aMinutes, aSeconds); |
221 | } |
222 | else if (aMinutes > 0) |
223 | { |
224 | Sprintf (aBuffer, "%02u:%02u", aMinutes, aSeconds); |
225 | } |
226 | else if (aSeconds > 0) |
227 | { |
228 | Sprintf (aBuffer, "%2u", aSeconds); |
229 | } |
230 | else |
231 | { |
232 | addInfo (theDict, theKey, aMilliSeconds); |
233 | return; |
234 | } |
235 | |
236 | addInfo (theDict, theKey, aBuffer); |
237 | } |
5e30547b |
238 | } |
239 | |
240 | // ======================================================================= |
241 | // function : Graphic3d_FrameStats |
242 | // purpose : |
243 | // ======================================================================= |
244 | Graphic3d_FrameStats::Graphic3d_FrameStats() |
245 | : myFpsTimer (Standard_True), |
246 | myFrameStartTime (0.0), |
247 | myFrameDuration (0.0), |
248 | myUpdateInterval (1.0), |
249 | myFpsFrameCount (0), |
250 | myCounters (0, 0), |
251 | myLastFrameIndex (0), |
252 | myIsLongLineFormat (Standard_False) |
253 | { |
254 | // |
255 | } |
256 | |
257 | // ======================================================================= |
258 | // function : ~Graphic3d_FrameStats |
259 | // purpose : |
260 | // ======================================================================= |
261 | Graphic3d_FrameStats::~Graphic3d_FrameStats() |
262 | { |
263 | // |
264 | } |
265 | |
266 | // ======================================================================= |
267 | // function : FormatStats |
268 | // purpose : |
269 | // ======================================================================= |
270 | TCollection_AsciiString Graphic3d_FrameStats::FormatStats (Graphic3d_RenderingParams::PerfCounters theFlags) const |
271 | { |
272 | const Standard_Integer aValWidth = 5; |
273 | std::stringstream aBuf; |
274 | const Standard_Boolean isCompact = theFlags == Graphic3d_RenderingParams::PerfCounters_FrameRate; // only FPS is displayed |
275 | const Graphic3d_FrameStatsData& aStats = LastDataFrame(); |
276 | if (myIsLongLineFormat |
277 | && (theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0 |
278 | && (theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0) |
279 | { |
280 | aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 9) << std::fixed << std::setprecision (1) << aStats.FrameRate() |
281 | << " [CPU: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 10) << std::fixed << std::setprecision (1) << aStats.FrameRateCpu() << "]\n"; |
282 | } |
283 | else |
284 | { |
285 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0) |
286 | { |
8f5760bc |
287 | aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << aStats.FrameRate(); |
288 | if (aStats.ImmediateFrameRate() > 0.0) |
289 | { |
290 | aBuf << " (" << std::fixed << std::setprecision (1) << aStats.ImmediateFrameRate() << ")"; |
291 | } |
292 | aBuf << "\n"; |
5e30547b |
293 | } |
294 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0) |
295 | { |
8f5760bc |
296 | aBuf << "CPU FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << aStats.FrameRateCpu(); |
297 | if (aStats.ImmediateFrameRateCpu() > 0.0) |
298 | { |
299 | aBuf << " (" << std::fixed << std::setprecision (1) << aStats.ImmediateFrameRateCpu() << ")"; |
300 | } |
301 | aBuf << "\n"; |
5e30547b |
302 | } |
303 | } |
304 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0) |
305 | { |
306 | if (myIsLongLineFormat) |
307 | { |
308 | formatCounter (aBuf, aValWidth, "Layers: ", aStats[Graphic3d_FrameStatsCounter_NbLayers]); |
309 | if (HasCulledLayers()) |
310 | { |
311 | formatCounter (aBuf, aValWidth, " [rendered: ", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled], "]"); |
312 | } |
313 | aBuf << "\n"; |
314 | } |
315 | else |
316 | { |
317 | formatCounter (aBuf, aValWidth + 3, "Layers: ", aStats[Graphic3d_FrameStatsCounter_NbLayers], "\n"); |
318 | } |
319 | } |
320 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0) |
321 | { |
322 | if (myIsLongLineFormat) |
323 | { |
324 | formatCounter (aBuf, aValWidth, "Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructs]); |
325 | if (HasCulledStructs()) |
326 | { |
327 | formatCounter (aBuf, aValWidth, " [rendered: ", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled], "]"); |
328 | } |
329 | aBuf << "\n"; |
330 | } |
331 | else |
332 | { |
333 | formatCounter (aBuf, aValWidth + 3, "Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructs], "\n"); |
334 | } |
335 | } |
8f5760bc |
336 | |
337 | const bool hasImmediate = aStats[Graphic3d_FrameStatsCounter_NbLayersImmediate] != 0 || aStats.ImmediateFrameRate() > 0.0; |
5e30547b |
338 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0 |
339 | || (theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0 |
340 | || (theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0 |
b9f43ad1 |
341 | || (theFlags & Graphic3d_RenderingParams::PerfCounters_Lines) != 0 |
5e30547b |
342 | || (theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0 |
343 | || (!myIsLongLineFormat |
344 | && ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0 |
345 | || (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0))) |
346 | { |
8f5760bc |
347 | if (hasImmediate) |
348 | { |
349 | aBuf << "Rendered (imm.)\n"; |
350 | } |
351 | else |
352 | { |
353 | aBuf << "Rendered\n"; |
354 | } |
5e30547b |
355 | } |
356 | if (!myIsLongLineFormat |
357 | && (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0) |
358 | { |
8f5760bc |
359 | formatCounterPair (aBuf, aValWidth, " Layers: ", |
360 | aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled], |
361 | aStats[Graphic3d_FrameStatsCounter_NbLayersImmediate], hasImmediate); |
5e30547b |
362 | } |
363 | if (!myIsLongLineFormat |
364 | && (theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0) |
365 | { |
8f5760bc |
366 | formatCounterPair (aBuf, aValWidth, " Structs: ", |
367 | aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled], |
368 | aStats[Graphic3d_FrameStatsCounter_NbStructsImmediate], hasImmediate); |
5e30547b |
369 | } |
370 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0) |
371 | { |
8f5760bc |
372 | formatCounterPair (aBuf, aValWidth, " Groups: ", |
373 | aStats[Graphic3d_FrameStatsCounter_NbGroupsNotCulled], |
374 | aStats[Graphic3d_FrameStatsCounter_NbGroupsImmediate], hasImmediate); |
5e30547b |
375 | } |
376 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0) |
377 | { |
8f5760bc |
378 | formatCounterPair (aBuf, aValWidth, " Arrays: ", |
379 | aStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled], |
380 | aStats[Graphic3d_FrameStatsCounter_NbElemsImmediate], hasImmediate); |
381 | formatCounterPair (aBuf, aValWidth, " [fill]: ", |
382 | aStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled], |
383 | aStats[Graphic3d_FrameStatsCounter_NbElemsFillImmediate], hasImmediate); |
384 | formatCounterPair (aBuf, aValWidth, " [line]: ", |
385 | aStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled], |
386 | aStats[Graphic3d_FrameStatsCounter_NbElemsLineImmediate], hasImmediate); |
387 | formatCounterPair (aBuf, aValWidth, " [point]: ", |
388 | aStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled], |
389 | aStats[Graphic3d_FrameStatsCounter_NbElemsPointImmediate], hasImmediate); |
390 | formatCounterPair (aBuf, aValWidth, " [text]: ", |
391 | aStats[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled], |
392 | aStats[Graphic3d_FrameStatsCounter_NbElemsTextImmediate], hasImmediate); |
5e30547b |
393 | } |
394 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0) |
395 | { |
8f5760bc |
396 | formatCounterPair (aBuf, aValWidth, " Triangles: ", |
397 | aStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled], |
398 | aStats[Graphic3d_FrameStatsCounter_NbTrianglesImmediate], hasImmediate); |
5e30547b |
399 | } |
b9f43ad1 |
400 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Lines) != 0) |
401 | { |
8f5760bc |
402 | formatCounterPair (aBuf, aValWidth, " Lines: ", |
403 | aStats[Graphic3d_FrameStatsCounter_NbLinesNotCulled], |
404 | aStats[Graphic3d_FrameStatsCounter_NbLinesImmediate], hasImmediate); |
b9f43ad1 |
405 | } |
5e30547b |
406 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0) |
407 | { |
8f5760bc |
408 | formatCounterPair (aBuf, aValWidth, " Points: ", |
409 | aStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled], |
410 | aStats[Graphic3d_FrameStatsCounter_NbPointsImmediate], hasImmediate); |
5e30547b |
411 | } |
412 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0) |
413 | { |
414 | aBuf << "GPU Memory\n"; |
415 | formatBytes (aBuf, aValWidth, " Geometry: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesGeom], "\n"); |
416 | formatBytes (aBuf, aValWidth, " Textures: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesTextures], "\n"); |
417 | formatBytes (aBuf, aValWidth, " Frames: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesFbos], "\n"); |
418 | } |
419 | |
420 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0) |
421 | { |
422 | aBuf << "Timers Average\n"; |
423 | formatTime (aBuf, aValWidth, " Elapsed Frame: ", aStats[Graphic3d_FrameStatsTimer_ElapsedFrame], "\n"); |
424 | formatTime (aBuf, aValWidth, " CPU Frame: ", aStats[Graphic3d_FrameStatsTimer_CpuFrame], "\n"); |
425 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0) |
426 | { |
427 | formatTime (aBuf, aValWidth, " CPU Picking: ", aStats[Graphic3d_FrameStatsTimer_CpuPicking], "\n"); |
428 | } |
429 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0) |
430 | { |
431 | formatTime (aBuf, aValWidth, " CPU Culling: ", aStats[Graphic3d_FrameStatsTimer_CpuCulling], "\n"); |
432 | } |
433 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics]) |
434 | { |
435 | formatTime (aBuf, aValWidth, " CPU Dynamics: ", aStats[Graphic3d_FrameStatsTimer_CpuDynamics], "\n"); |
436 | } |
437 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTimeMax) != 0) |
438 | { |
439 | aBuf << "Timers Max\n"; |
440 | formatTime (aBuf, aValWidth, " CPU Frame: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuFrame], "\n"); |
441 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0) |
442 | { |
443 | formatTime (aBuf, aValWidth, " CPU Picking: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking], "\n"); |
444 | } |
445 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0) |
446 | { |
447 | formatTime (aBuf, aValWidth, " CPU Culling: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling], "\n"); |
448 | } |
449 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics]) |
450 | { |
451 | formatTime (aBuf, aValWidth, " CPU Dynamics: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics], "\n"); |
452 | } |
453 | } |
454 | } |
455 | |
456 | return TCollection_AsciiString (aBuf.str().c_str()); |
457 | } |
458 | |
79b544e6 |
459 | // ======================================================================= |
460 | // function : FormatStats |
461 | // purpose : |
462 | // ======================================================================= |
463 | void Graphic3d_FrameStats::FormatStats (TColStd_IndexedDataMapOfStringString& theDict, |
464 | Graphic3d_RenderingParams::PerfCounters theFlags) const |
465 | { |
466 | const Graphic3d_FrameStatsData& aStats = LastDataFrame(); |
467 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0) |
468 | { |
469 | addInfo (theDict, "FPS", aStats.FrameRate()); |
470 | } |
471 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0) |
472 | { |
473 | addInfo (theDict, "CPU FPS", aStats.FrameRateCpu()); |
474 | } |
475 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0) |
476 | { |
477 | addInfo (theDict, "Layers", aStats[Graphic3d_FrameStatsCounter_NbLayers]); |
478 | if (HasCulledLayers()) |
479 | { |
480 | addInfo (theDict, "Rendered layers", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled]); |
481 | } |
482 | } |
483 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0) |
484 | { |
485 | addInfo (theDict, "Structs", aStats[Graphic3d_FrameStatsCounter_NbStructs]); |
486 | if (HasCulledStructs()) |
487 | { |
488 | addInfo (theDict, "Rendered structs", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled]); |
489 | } |
490 | } |
491 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0) |
492 | { |
493 | addInfo (theDict, "Rendered groups", aStats[Graphic3d_FrameStatsCounter_NbGroupsNotCulled]); |
494 | } |
495 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0) |
496 | { |
497 | addInfo (theDict, "Rendered arrays", aStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled]); |
498 | addInfo (theDict, "Rendered [fill] arrays", aStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled]); |
499 | addInfo (theDict, "Rendered [line] arrays", aStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled]); |
500 | addInfo (theDict, "Rendered [point] arrays", aStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled]); |
501 | addInfo (theDict, "Rendered [text] arrays", aStats[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled]); |
502 | } |
503 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0) |
504 | { |
505 | addInfo (theDict, "Rendered triangles", aStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled]); |
506 | } |
b9f43ad1 |
507 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Lines) != 0) |
508 | { |
509 | addInfo (theDict, "Rendered lines", aStats[Graphic3d_FrameStatsCounter_NbLinesNotCulled]); |
510 | } |
79b544e6 |
511 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0) |
512 | { |
513 | addInfo (theDict, "Rendered points", aStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled]); |
514 | } |
515 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0) |
516 | { |
517 | addInfo (theDict, "GPU Memory [geometry]", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesGeom]); |
518 | addInfo (theDict, "GPU Memory [textures]", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesTextures]); |
519 | addInfo (theDict, "GPU Memory [frames]", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesFbos]); |
520 | } |
521 | |
522 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0) |
523 | { |
524 | addTimeInfo (theDict, "Elapsed Frame (average)", aStats[Graphic3d_FrameStatsTimer_ElapsedFrame]); |
525 | addTimeInfo (theDict, "CPU Frame (average)", aStats[Graphic3d_FrameStatsTimer_CpuFrame]); |
526 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0) |
527 | { |
528 | addTimeInfo (theDict, "CPU Picking (average)", aStats[Graphic3d_FrameStatsTimer_CpuPicking]); |
529 | } |
530 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0) |
531 | { |
532 | addTimeInfo (theDict, "CPU Culling (average)", aStats[Graphic3d_FrameStatsTimer_CpuCulling]); |
533 | } |
534 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics]) |
535 | { |
536 | addTimeInfo (theDict, "CPU Dynamics (average)", aStats[Graphic3d_FrameStatsTimer_CpuDynamics]); |
537 | } |
538 | if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTimeMax) != 0) |
539 | { |
540 | addTimeInfo (theDict, "CPU Frame (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuFrame]); |
541 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0) |
542 | { |
543 | addTimeInfo (theDict, "CPU Picking (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking]); |
544 | } |
545 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0) |
546 | { |
547 | addTimeInfo (theDict, "CPU Culling (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling]); |
548 | } |
549 | if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics]) |
550 | { |
551 | addTimeInfo (theDict, "CPU Dynamics (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics]); |
552 | } |
553 | } |
554 | } |
555 | } |
556 | |
5e30547b |
557 | // ======================================================================= |
558 | // function : FrameStart |
559 | // purpose : |
560 | // ======================================================================= |
561 | void Graphic3d_FrameStats::FrameStart (const Handle(Graphic3d_CView)& theView, |
562 | bool theIsImmediateOnly) |
563 | { |
564 | const Graphic3d_RenderingParams::PerfCounters aBits = !theView.IsNull() |
565 | ? theView->RenderingParams().CollectedStats |
566 | : Graphic3d_RenderingParams::PerfCounters_NONE; |
567 | if (theIsImmediateOnly |
568 | && (aBits & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0) |
569 | { |
570 | return; |
571 | } |
572 | |
573 | const Standard_Integer aNbFrames = Max (!theView.IsNull() |
574 | ? theView->RenderingParams().StatsNbFrames |
575 | : 1, 1); |
576 | if (myCounters.Size() != aNbFrames) |
577 | { |
578 | myCounters.Resize (0, aNbFrames - 1, false); |
579 | myCounters.Init (Graphic3d_FrameStatsData()); |
580 | myLastFrameIndex = myCounters.Upper(); |
581 | } |
582 | |
583 | // reset values at the end of frame (after data has been flushed), |
584 | // so that application can put some counters (like picking time) before FrameStart(). |
585 | //myCountersTmp.Reset(); |
586 | |
587 | myFrameStartTime = myFpsTimer.ElapsedTime(); |
588 | if (!myFpsTimer.IsStarted()) |
589 | { |
590 | myFpsTimer.Reset(); |
591 | myFpsTimer.Start(); |
592 | myFpsFrameCount = 0; |
593 | } |
594 | } |
595 | |
596 | // ======================================================================= |
597 | // function : FrameEnd |
598 | // purpose : |
599 | // ======================================================================= |
600 | void Graphic3d_FrameStats::FrameEnd (const Handle(Graphic3d_CView)& theView, |
601 | bool theIsImmediateOnly) |
602 | { |
603 | const Graphic3d_RenderingParams::PerfCounters aBits = !theView.IsNull() |
604 | ? theView->RenderingParams().CollectedStats |
605 | : Graphic3d_RenderingParams::PerfCounters_NONE; |
606 | if (theIsImmediateOnly |
607 | && (aBits & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0) |
608 | { |
609 | return; |
610 | } |
611 | |
612 | const double aTime = myFpsTimer.ElapsedTime(); |
613 | myFrameDuration = aTime - myFrameStartTime; |
614 | ++myFpsFrameCount; |
615 | if (!theView.IsNull()) |
616 | { |
617 | myUpdateInterval = theView->RenderingParams().StatsUpdateInterval; |
618 | } |
619 | |
620 | if (aTime < myUpdateInterval) |
621 | { |
622 | myCountersTmp.FlushTimers (myFpsFrameCount, false); |
623 | return; |
624 | } |
625 | |
8f5760bc |
626 | const Graphic3d_FrameStatsData& aPrevFrame = myCounters.Value (myLastFrameIndex); |
5e30547b |
627 | if (aTime > gp::Resolution()) |
628 | { |
629 | // update FPS |
630 | myFpsTimer.Stop(); |
631 | const double aCpuSec = myFpsTimer.UserTimeCPU(); |
5e30547b |
632 | myCountersTmp[Graphic3d_FrameStatsTimer_ElapsedFrame] = aTime; |
633 | myCountersTmp[Graphic3d_FrameStatsTimer_CpuFrame] = aCpuSec; |
8f5760bc |
634 | |
635 | if (theIsImmediateOnly) |
636 | { |
637 | myCountersTmp.ChangeImmediateFrameRate() = double(myFpsFrameCount) / aTime; |
638 | myCountersTmp.ChangeImmediateFrameRateCpu() = aCpuSec > gp::Resolution() |
639 | ? double(myFpsFrameCount) / aCpuSec |
640 | : -1.0; |
641 | myCountersTmp.ChangeFrameRate() = aPrevFrame.FrameRate(); |
642 | myCountersTmp.ChangeFrameRateCpu() = aPrevFrame.FrameRateCpu(); |
643 | } |
644 | else |
645 | { |
646 | myCountersTmp.ChangeImmediateFrameRate() = -1.0; |
647 | myCountersTmp.ChangeImmediateFrameRateCpu() = -1.0; |
648 | myCountersTmp.ChangeFrameRate() = double(myFpsFrameCount) / aTime; |
649 | myCountersTmp.ChangeFrameRateCpu() = aCpuSec > gp::Resolution() |
650 | ? double(myFpsFrameCount) / aCpuSec |
651 | : -1.0; |
652 | } |
5e30547b |
653 | myCountersTmp.FlushTimers (myFpsFrameCount, true); |
654 | myCountersMax.FillMax (myCountersTmp); |
655 | myFpsTimer.Reset(); |
656 | myFpsTimer.Start(); |
657 | myFpsFrameCount = 0; |
658 | } |
659 | |
660 | // update structure counters |
661 | if (theView.IsNull()) |
662 | { |
663 | myCounters.SetValue (myLastFrameIndex, myCountersTmp); |
664 | myCountersTmp.Reset(); |
665 | return; |
666 | } |
667 | |
668 | updateStatistics (theView, theIsImmediateOnly); |
669 | |
670 | if (++myLastFrameIndex > myCounters.Upper()) |
671 | { |
672 | myLastFrameIndex = myCounters.Lower(); |
673 | } |
8f5760bc |
674 | if (theIsImmediateOnly) |
675 | { |
676 | // copy rendered counters collected for immediate layers |
677 | const Standard_Integer anImmShift = Graphic3d_FrameStatsCounter_IMMEDIATE_LOWER - Graphic3d_FrameStatsCounter_RENDERED_LOWER; |
678 | Standard_STATIC_ASSERT((Graphic3d_FrameStatsCounter_RENDERED_UPPER - Graphic3d_FrameStatsCounter_RENDERED_LOWER) == (Graphic3d_FrameStatsCounter_IMMEDIATE_UPPER - Graphic3d_FrameStatsCounter_IMMEDIATE_LOWER)) |
679 | for (Standard_Integer aCntIter = Graphic3d_FrameStatsCounter_RENDERED_LOWER; aCntIter <= Graphic3d_FrameStatsCounter_RENDERED_UPPER; ++aCntIter) |
680 | { |
681 | myCountersTmp.ChangeCounterValue ((Graphic3d_FrameStatsCounter )(aCntIter + anImmShift)) = myCountersTmp.CounterValue ((Graphic3d_FrameStatsCounter )aCntIter); |
682 | } |
683 | |
684 | // copy main rendered counters from previous non-immediate frame |
685 | for (Standard_Integer aCntIter = Graphic3d_FrameStatsCounter_RENDERED_LOWER; aCntIter <= Graphic3d_FrameStatsCounter_RENDERED_UPPER; ++aCntIter) |
686 | { |
687 | myCountersTmp.ChangeCounterValue ((Graphic3d_FrameStatsCounter )aCntIter) = aPrevFrame.CounterValue ((Graphic3d_FrameStatsCounter )aCntIter); |
688 | } |
689 | myCountersTmp.ChangeCounterValue (Graphic3d_FrameStatsCounter_EstimatedBytesGeom) = aPrevFrame.CounterValue (Graphic3d_FrameStatsCounter_EstimatedBytesGeom); |
690 | } |
5e30547b |
691 | myCounters.SetValue (myLastFrameIndex, myCountersTmp); |
692 | myCountersTmp.Reset(); |
693 | } |