0031505: Point Cloud Rendering - fix on-screen statistics about number of visible...
[occt.git] / src / Graphic3d / Graphic3d_FrameStats.cxx
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;
52     }
53     if (thePostfix != NULL)
54     {
55       theStream << thePostfix;
56     }
57     return theStream;
58   }
59
60   //! Format memory counter.
61   static std::ostream& formatBytes (std::ostream& theStream,
62                                     Standard_Integer theWidth,
63                                     const char* thePrefix,
64                                     Standard_Size theValue,
65                                     const char* thePostfix = NULL)
66   {
67     if (thePrefix != NULL)
68     {
69       theStream << thePrefix;
70     }
71     theStream << std::setfill(' ') << std::setw (theWidth);
72     if (theValue >= 1024 * 1024 * 1024)
73     {
74       Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0 * 1024.0);
75       theStream << std::fixed << std::setprecision (1) << aValM << " GiB";
76     }
77     else if (theValue >= 1024 * 1024)
78     {
79       Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0);
80       theStream << std::fixed << std::setprecision (1) << aValM << " MiB";
81     }
82     else if (theValue >= 1024)
83     {
84       Standard_Real aValK = Standard_Real(theValue) / 1024.0;
85       theStream << std::fixed << std::setprecision (1) << aValK << " KiB";
86     }
87     else
88     {
89       theStream << theValue << " B";
90     }
91     if (thePostfix != NULL)
92     {
93       theStream << thePostfix;
94     }
95     return theStream;
96   }
97
98   static const Standard_Real THE_SECONDS_IN_HOUR = 3600.0;
99   static const Standard_Real THE_SECONDS_IN_MINUTE = 60.0;
100   static const Standard_Real THE_SECOND_IN_HOUR   = 1.0 / THE_SECONDS_IN_HOUR;
101   static const Standard_Real THE_SECOND_IN_MINUTE = 1.0 / THE_SECONDS_IN_MINUTE;
102
103   //! Format time.
104   static std::ostream& formatTime (std::ostream& theStream,
105                                    Standard_Integer theWidth,
106                                    const char* thePrefix,
107                                    Standard_Real theSeconds,
108                                    const char* thePostfix = NULL)
109   {
110     if (thePrefix != NULL)
111     {
112       theStream << thePrefix;
113     }
114
115     Standard_Real aSecIn = theSeconds;
116     unsigned int aHours   = (unsigned int )(aSecIn * THE_SECOND_IN_HOUR);
117     aSecIn -= Standard_Real(aHours) * THE_SECONDS_IN_HOUR;
118     unsigned int aMinutes = (unsigned int )(aSecIn * THE_SECOND_IN_MINUTE);
119     aSecIn -= Standard_Real(aMinutes) * THE_SECONDS_IN_MINUTE;
120     unsigned int aSeconds = (unsigned int )aSecIn;
121     aSecIn -= Standard_Real(aSeconds);
122     Standard_Real aMilliSeconds = 1000.0 * aSecIn;
123
124     char aBuffer[64];
125     theStream << std::setfill(' ') << std::setw (theWidth);
126     if (aHours > 0)
127     {
128       Sprintf (aBuffer, "%02u:%02u:%02u", aHours, aMinutes, aSeconds);
129       theStream << aBuffer;
130     }
131     else if (aMinutes > 0)
132     {
133       Sprintf (aBuffer, "%02u:%02u", aMinutes, aSeconds);
134       theStream << aBuffer;
135     }
136     else if (aSeconds > 0)
137     {
138       Sprintf (aBuffer, "%2u s", aSeconds);
139       theStream << aBuffer;
140     }
141     else
142     {
143       theStream << std::fixed << std::setprecision (1) << aMilliSeconds << " ms";
144     }
145
146     if (thePostfix != NULL)
147     {
148       theStream << thePostfix;
149     }
150     return theStream;
151   }
152
153   //! Add key-value pair to the dictionary.
154   static void addInfo (TColStd_IndexedDataMapOfStringString& theDict,
155                        const TCollection_AsciiString&        theKey,
156                        const char*                           theValue)
157   {
158     TCollection_AsciiString aValue (theValue != NULL ? theValue : "");
159     theDict.ChangeFromIndex (theDict.Add (theKey, aValue)) = aValue;
160   }
161
162   //! Add key-value pair to the dictionary.
163   static void addInfo (TColStd_IndexedDataMapOfStringString& theDict,
164                        const TCollection_AsciiString&        theKey,
165                        const Standard_Real                   theValue)
166   {
167     char aTmp[50];
168     Sprintf (aTmp, "%.1g", theValue);
169     addInfo (theDict, theKey, aTmp);
170   }
171
172   //! Add key-value pair to the dictionary.
173   static void addInfo (TColStd_IndexedDataMapOfStringString& theDict,
174                        const TCollection_AsciiString&        theKey,
175                        const Standard_Size                   theValue)
176   {
177     char aTmp[50];
178     Sprintf (aTmp, "%zu", theValue);
179     addInfo (theDict, theKey, aTmp);
180   }
181
182   //! Format time.
183   static void addTimeInfo (TColStd_IndexedDataMapOfStringString& theDict,
184                            const TCollection_AsciiString&        theKey,
185                            Standard_Real                         theSeconds)
186   {
187     Standard_Real aSecIn = theSeconds;
188     unsigned int aHours   = (unsigned int )(aSecIn * THE_SECOND_IN_HOUR);
189     aSecIn -= Standard_Real(aHours) * THE_SECONDS_IN_HOUR;
190     unsigned int aMinutes = (unsigned int )(aSecIn * THE_SECOND_IN_MINUTE);
191     aSecIn -= Standard_Real(aMinutes) * THE_SECONDS_IN_MINUTE;
192     unsigned int aSeconds = (unsigned int )aSecIn;
193     aSecIn -= Standard_Real(aSeconds);
194     Standard_Real aMilliSeconds = 1000.0 * aSecIn;
195
196     char aBuffer[64];
197     if (aHours > 0)
198     {
199       Sprintf (aBuffer, "%02u:%02u:%02u", aHours, aMinutes, aSeconds);
200     }
201     else if (aMinutes > 0)
202     {
203       Sprintf (aBuffer, "%02u:%02u", aMinutes, aSeconds);
204     }
205     else if (aSeconds > 0)
206     {
207       Sprintf (aBuffer, "%2u", aSeconds);
208     }
209     else
210     {
211       addInfo (theDict, theKey, aMilliSeconds);
212       return;
213     }
214     
215     addInfo (theDict, theKey, aBuffer);
216   }
217 }
218
219 // =======================================================================
220 // function : Graphic3d_FrameStats
221 // purpose  :
222 // =======================================================================
223 Graphic3d_FrameStats::Graphic3d_FrameStats()
224 : myFpsTimer (Standard_True),
225   myFrameStartTime (0.0),
226   myFrameDuration  (0.0),
227   myUpdateInterval (1.0),
228   myFpsFrameCount (0),
229   myCounters (0, 0),
230   myLastFrameIndex (0),
231   myIsLongLineFormat (Standard_False)
232 {
233   //
234 }
235
236 // =======================================================================
237 // function : ~Graphic3d_FrameStats
238 // purpose  :
239 // =======================================================================
240 Graphic3d_FrameStats::~Graphic3d_FrameStats()
241 {
242   //
243 }
244
245 // =======================================================================
246 // function : FormatStats
247 // purpose  :
248 // =======================================================================
249 TCollection_AsciiString Graphic3d_FrameStats::FormatStats (Graphic3d_RenderingParams::PerfCounters theFlags) const
250 {
251   const Standard_Integer aValWidth = 5;
252   std::stringstream aBuf;
253   const Standard_Boolean isCompact = theFlags == Graphic3d_RenderingParams::PerfCounters_FrameRate; // only FPS is displayed
254   const Graphic3d_FrameStatsData& aStats = LastDataFrame();
255   if (myIsLongLineFormat
256    && (theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0
257    && (theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
258   {
259     aBuf << "FPS: "     << std::setfill(' ') << std::setw (isCompact ? aValWidth : 9)  << std::fixed << std::setprecision (1) << aStats.FrameRate()
260          << " [CPU: "   << std::setfill(' ') << std::setw (isCompact ? aValWidth : 10) << std::fixed << std::setprecision (1) << aStats.FrameRateCpu() << "]\n";
261   }
262   else
263   {
264     if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
265     {
266       aBuf << "FPS:     " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << aStats.FrameRate()  << "\n";
267     }
268     if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
269     {
270       aBuf << "CPU FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << aStats.FrameRateCpu() << "\n";
271     }
272   }
273   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
274   {
275     if (myIsLongLineFormat)
276     {
277       formatCounter (aBuf, aValWidth, "Layers:  ", aStats[Graphic3d_FrameStatsCounter_NbLayers]);
278       if (HasCulledLayers())
279       {
280         formatCounter (aBuf, aValWidth, " [rendered: ", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled], "]");
281       }
282       aBuf << "\n";
283     }
284     else
285     {
286       formatCounter (aBuf, aValWidth + 3, "Layers:  ", aStats[Graphic3d_FrameStatsCounter_NbLayers], "\n");
287     }
288   }
289   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
290   {
291     if (myIsLongLineFormat)
292     {
293       formatCounter (aBuf, aValWidth, "Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructs]);
294       if (HasCulledStructs())
295       {
296         formatCounter (aBuf, aValWidth, " [rendered: ", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled], "]");
297       }
298       aBuf << "\n";
299     }
300     else
301     {
302       formatCounter (aBuf, aValWidth + 3, "Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructs], "\n");
303     }
304   }
305   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0
306    || (theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0
307    || (theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
308    || (theFlags & Graphic3d_RenderingParams::PerfCounters_Lines) != 0
309    || (theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0
310    || (!myIsLongLineFormat
311     && ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
312      || (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)))
313   {
314     aBuf << "Rendered\n";
315   }
316   if (!myIsLongLineFormat
317    && (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
318   {
319     formatCounter (aBuf, aValWidth, "    Layers: ", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled], "\n");
320   }
321   if (!myIsLongLineFormat
322    && (theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
323   {
324     formatCounter (aBuf, aValWidth, "   Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled], "\n");
325   }
326   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
327   {
328     formatCounter (aBuf, aValWidth, "    Groups: ", aStats[Graphic3d_FrameStatsCounter_NbGroupsNotCulled], "\n");
329   }
330   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
331   {
332     formatCounter (aBuf, aValWidth, "    Arrays: ", aStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled], "\n");
333     formatCounter (aBuf, aValWidth, "    [fill]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled], "\n");
334     formatCounter (aBuf, aValWidth, "    [line]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled], "\n");
335     formatCounter (aBuf, aValWidth, "   [point]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled], "\n");
336     formatCounter (aBuf, aValWidth, "    [text]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled], "\n");
337   }
338   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
339   {
340     formatCounter (aBuf, aValWidth, " Triangles: ", aStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled], "\n");
341   }
342   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
343   {
344     formatCounter (aBuf, aValWidth, "     Lines: ", aStats[Graphic3d_FrameStatsCounter_NbLinesNotCulled], "\n");
345   }
346   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
347   {
348     formatCounter (aBuf, aValWidth, "    Points: ", aStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled], "\n");
349   }
350   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
351   {
352     aBuf << "GPU Memory\n";
353     formatBytes (aBuf, aValWidth, "  Geometry: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesGeom], "\n");
354     formatBytes (aBuf, aValWidth, "  Textures: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesTextures], "\n");
355     formatBytes (aBuf, aValWidth, "    Frames: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesFbos], "\n");
356   }
357
358   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
359   {
360     aBuf << "Timers Average\n";
361     formatTime (aBuf, aValWidth, " Elapsed Frame: ", aStats[Graphic3d_FrameStatsTimer_ElapsedFrame], "\n");
362     formatTime (aBuf, aValWidth, "     CPU Frame: ", aStats[Graphic3d_FrameStatsTimer_CpuFrame], "\n");
363     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
364     {
365       formatTime (aBuf, aValWidth, "   CPU Picking: ", aStats[Graphic3d_FrameStatsTimer_CpuPicking], "\n");
366     }
367     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
368     {
369       formatTime (aBuf, aValWidth, "   CPU Culling: ", aStats[Graphic3d_FrameStatsTimer_CpuCulling], "\n");
370     }
371     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
372     {
373       formatTime (aBuf, aValWidth, "  CPU Dynamics: ", aStats[Graphic3d_FrameStatsTimer_CpuDynamics], "\n");
374     }
375     if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTimeMax) != 0)
376     {
377       aBuf << "Timers Max\n";
378       formatTime (aBuf, aValWidth, "     CPU Frame: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuFrame], "\n");
379       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
380       {
381         formatTime (aBuf, aValWidth, "   CPU Picking: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking], "\n");
382       }
383       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
384       {
385         formatTime (aBuf, aValWidth, "   CPU Culling: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling], "\n");
386       }
387       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
388       {
389         formatTime (aBuf, aValWidth, "  CPU Dynamics: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics], "\n");
390       }
391     }
392   }
393
394   return TCollection_AsciiString (aBuf.str().c_str());
395 }
396
397 // =======================================================================
398 // function : FormatStats
399 // purpose  :
400 // =======================================================================
401 void Graphic3d_FrameStats::FormatStats (TColStd_IndexedDataMapOfStringString&   theDict,
402                                         Graphic3d_RenderingParams::PerfCounters theFlags) const
403 {
404   const Graphic3d_FrameStatsData& aStats = LastDataFrame();
405   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
406   {
407     addInfo (theDict, "FPS", aStats.FrameRate());
408   }
409   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
410   {
411     addInfo (theDict, "CPU FPS", aStats.FrameRateCpu());
412   }
413   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
414   {
415     addInfo (theDict, "Layers", aStats[Graphic3d_FrameStatsCounter_NbLayers]);
416     if (HasCulledLayers())
417     {
418       addInfo (theDict, "Rendered layers", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled]);
419     }
420   }
421   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
422   {
423     addInfo (theDict, "Structs", aStats[Graphic3d_FrameStatsCounter_NbStructs]);
424     if (HasCulledStructs())
425     {
426       addInfo (theDict, "Rendered structs", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled]);
427     }
428   }
429   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
430   {
431     addInfo (theDict, "Rendered groups", aStats[Graphic3d_FrameStatsCounter_NbGroupsNotCulled]);
432   }
433   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
434   {
435     addInfo (theDict, "Rendered arrays",         aStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled]);
436     addInfo (theDict, "Rendered [fill] arrays",  aStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled]);
437     addInfo (theDict, "Rendered [line] arrays",  aStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled]);
438     addInfo (theDict, "Rendered [point] arrays", aStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled]);
439     addInfo (theDict, "Rendered [text] arrays",  aStats[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled]);
440   }
441   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
442   {
443     addInfo (theDict, "Rendered triangles", aStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled]);
444   }
445   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
446   {
447     addInfo (theDict, "Rendered lines", aStats[Graphic3d_FrameStatsCounter_NbLinesNotCulled]);
448   }
449   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
450   {
451     addInfo (theDict, "Rendered points", aStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled]);
452   }
453   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
454   {
455     addInfo (theDict, "GPU Memory [geometry]", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesGeom]);
456     addInfo (theDict, "GPU Memory [textures]", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesTextures]);
457     addInfo (theDict, "GPU Memory [frames]",   aStats[Graphic3d_FrameStatsCounter_EstimatedBytesFbos]);
458   }
459
460   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
461   {
462     addTimeInfo (theDict, "Elapsed Frame (average)", aStats[Graphic3d_FrameStatsTimer_ElapsedFrame]);
463     addTimeInfo (theDict, "CPU Frame (average)",     aStats[Graphic3d_FrameStatsTimer_CpuFrame]);
464     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
465     {
466       addTimeInfo (theDict, "CPU Picking (average)", aStats[Graphic3d_FrameStatsTimer_CpuPicking]);
467     }
468     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
469     {
470       addTimeInfo (theDict, "CPU Culling (average)", aStats[Graphic3d_FrameStatsTimer_CpuCulling]);
471     }
472     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
473     {
474       addTimeInfo (theDict, "CPU Dynamics (average)", aStats[Graphic3d_FrameStatsTimer_CpuDynamics]);
475     }
476     if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTimeMax) != 0)
477     {
478       addTimeInfo (theDict, "CPU Frame (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuFrame]);
479       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
480       {
481         addTimeInfo (theDict, "CPU Picking (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking]);
482       }
483       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
484       {
485         addTimeInfo (theDict, "CPU Culling (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling]);
486       }
487       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
488       {
489         addTimeInfo (theDict, "CPU Dynamics (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics]);
490       }
491     }
492   }
493 }
494
495 // =======================================================================
496 // function : FrameStart
497 // purpose  :
498 // =======================================================================
499 void Graphic3d_FrameStats::FrameStart (const Handle(Graphic3d_CView)& theView,
500                                        bool theIsImmediateOnly)
501 {
502   const Graphic3d_RenderingParams::PerfCounters aBits = !theView.IsNull()
503                                                       ? theView->RenderingParams().CollectedStats
504                                                       : Graphic3d_RenderingParams::PerfCounters_NONE;
505   if (theIsImmediateOnly
506    && (aBits & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
507   {
508     return;
509   }
510
511   const Standard_Integer aNbFrames = Max (!theView.IsNull()
512                                          ? theView->RenderingParams().StatsNbFrames
513                                          : 1, 1);
514   if (myCounters.Size() != aNbFrames)
515   {
516     myCounters.Resize (0, aNbFrames - 1, false);
517     myCounters.Init (Graphic3d_FrameStatsData());
518     myLastFrameIndex = myCounters.Upper();
519   }
520
521   // reset values at the end of frame (after data has been flushed),
522   // so that application can put some counters (like picking time) before FrameStart().
523   //myCountersTmp.Reset();
524
525   myFrameStartTime = myFpsTimer.ElapsedTime();
526   if (!myFpsTimer.IsStarted())
527   {
528     myFpsTimer.Reset();
529     myFpsTimer.Start();
530     myFpsFrameCount = 0;
531   }
532 }
533
534 // =======================================================================
535 // function : FrameEnd
536 // purpose  :
537 // =======================================================================
538 void Graphic3d_FrameStats::FrameEnd (const Handle(Graphic3d_CView)& theView,
539                                      bool theIsImmediateOnly)
540 {
541   const Graphic3d_RenderingParams::PerfCounters aBits = !theView.IsNull()
542                                                       ? theView->RenderingParams().CollectedStats
543                                                       : Graphic3d_RenderingParams::PerfCounters_NONE;
544   if (theIsImmediateOnly
545    && (aBits & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
546   {
547     return;
548   }
549
550   const double aTime = myFpsTimer.ElapsedTime();
551   myFrameDuration = aTime - myFrameStartTime;
552   ++myFpsFrameCount;
553   if (!theView.IsNull())
554   {
555     myUpdateInterval = theView->RenderingParams().StatsUpdateInterval;
556   }
557
558   if (aTime < myUpdateInterval)
559   {
560     myCountersTmp.FlushTimers (myFpsFrameCount, false);
561     return;
562   }
563
564   if (aTime > gp::Resolution())
565   {
566     // update FPS
567     myFpsTimer.Stop();
568     const double aCpuSec = myFpsTimer.UserTimeCPU();
569
570     myCountersTmp[Graphic3d_FrameStatsTimer_ElapsedFrame]  = aTime;
571     myCountersTmp[Graphic3d_FrameStatsTimer_CpuFrame]      = aCpuSec;
572     myCountersTmp.ChangeFrameRate()    = double(myFpsFrameCount) / aTime;
573     myCountersTmp.ChangeFrameRateCpu() = aCpuSec > gp::Resolution()
574                                        ? double(myFpsFrameCount) / aCpuSec
575                                        : -1.0;
576     myCountersTmp.FlushTimers (myFpsFrameCount, true);
577     myCountersMax.FillMax (myCountersTmp);
578     myFpsTimer.Reset();
579     myFpsTimer.Start();
580     myFpsFrameCount = 0;
581   }
582
583   // update structure counters
584   if (theView.IsNull())
585   {
586     myCounters.SetValue (myLastFrameIndex, myCountersTmp);
587     myCountersTmp.Reset();
588     return;
589   }
590
591   updateStatistics (theView, theIsImmediateOnly);
592
593   if (++myLastFrameIndex > myCounters.Upper())
594   {
595     myLastFrameIndex = myCounters.Lower();
596   }
597   myCounters.SetValue (myLastFrameIndex, myCountersTmp);
598   myCountersTmp.Reset();
599 }