0030437: Visualization, TKV3d - add Draw command to print rendering statistics
[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_Points) != 0
309    || (!myIsLongLineFormat
310     && ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
311      || (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)))
312   {
313     aBuf << "Rendered\n";
314   }
315   if (!myIsLongLineFormat
316    && (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
317   {
318     formatCounter (aBuf, aValWidth, "    Layers: ", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled], "\n");
319   }
320   if (!myIsLongLineFormat
321    && (theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
322   {
323     formatCounter (aBuf, aValWidth, "   Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled], "\n");
324   }
325   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
326   {
327     formatCounter (aBuf, aValWidth, "    Groups: ", aStats[Graphic3d_FrameStatsCounter_NbGroupsNotCulled], "\n");
328   }
329   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
330   {
331     formatCounter (aBuf, aValWidth, "    Arrays: ", aStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled], "\n");
332     formatCounter (aBuf, aValWidth, "    [fill]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled], "\n");
333     formatCounter (aBuf, aValWidth, "    [line]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled], "\n");
334     formatCounter (aBuf, aValWidth, "   [point]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled], "\n");
335     formatCounter (aBuf, aValWidth, "    [text]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled], "\n");
336   }
337   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
338   {
339     formatCounter (aBuf, aValWidth, " Triangles: ", aStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled], "\n");
340   }
341   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
342   {
343     formatCounter (aBuf, aValWidth, "    Points: ", aStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled], "\n");
344   }
345   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
346   {
347     aBuf << "GPU Memory\n";
348     formatBytes (aBuf, aValWidth, "  Geometry: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesGeom], "\n");
349     formatBytes (aBuf, aValWidth, "  Textures: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesTextures], "\n");
350     formatBytes (aBuf, aValWidth, "    Frames: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesFbos], "\n");
351   }
352
353   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
354   {
355     aBuf << "Timers Average\n";
356     formatTime (aBuf, aValWidth, " Elapsed Frame: ", aStats[Graphic3d_FrameStatsTimer_ElapsedFrame], "\n");
357     formatTime (aBuf, aValWidth, "     CPU Frame: ", aStats[Graphic3d_FrameStatsTimer_CpuFrame], "\n");
358     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
359     {
360       formatTime (aBuf, aValWidth, "   CPU Picking: ", aStats[Graphic3d_FrameStatsTimer_CpuPicking], "\n");
361     }
362     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
363     {
364       formatTime (aBuf, aValWidth, "   CPU Culling: ", aStats[Graphic3d_FrameStatsTimer_CpuCulling], "\n");
365     }
366     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
367     {
368       formatTime (aBuf, aValWidth, "  CPU Dynamics: ", aStats[Graphic3d_FrameStatsTimer_CpuDynamics], "\n");
369     }
370     if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTimeMax) != 0)
371     {
372       aBuf << "Timers Max\n";
373       formatTime (aBuf, aValWidth, "     CPU Frame: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuFrame], "\n");
374       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
375       {
376         formatTime (aBuf, aValWidth, "   CPU Picking: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking], "\n");
377       }
378       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
379       {
380         formatTime (aBuf, aValWidth, "   CPU Culling: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling], "\n");
381       }
382       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
383       {
384         formatTime (aBuf, aValWidth, "  CPU Dynamics: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics], "\n");
385       }
386     }
387   }
388
389   return TCollection_AsciiString (aBuf.str().c_str());
390 }
391
392 // =======================================================================
393 // function : FormatStats
394 // purpose  :
395 // =======================================================================
396 void Graphic3d_FrameStats::FormatStats (TColStd_IndexedDataMapOfStringString&   theDict,
397                                         Graphic3d_RenderingParams::PerfCounters theFlags) const
398 {
399   const Graphic3d_FrameStatsData& aStats = LastDataFrame();
400   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
401   {
402     addInfo (theDict, "FPS", aStats.FrameRate());
403   }
404   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
405   {
406     addInfo (theDict, "CPU FPS", aStats.FrameRateCpu());
407   }
408   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
409   {
410     addInfo (theDict, "Layers", aStats[Graphic3d_FrameStatsCounter_NbLayers]);
411     if (HasCulledLayers())
412     {
413       addInfo (theDict, "Rendered layers", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled]);
414     }
415   }
416   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
417   {
418     addInfo (theDict, "Structs", aStats[Graphic3d_FrameStatsCounter_NbStructs]);
419     if (HasCulledStructs())
420     {
421       addInfo (theDict, "Rendered structs", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled]);
422     }
423   }
424   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
425   {
426     addInfo (theDict, "Rendered groups", aStats[Graphic3d_FrameStatsCounter_NbGroupsNotCulled]);
427   }
428   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
429   {
430     addInfo (theDict, "Rendered arrays",         aStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled]);
431     addInfo (theDict, "Rendered [fill] arrays",  aStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled]);
432     addInfo (theDict, "Rendered [line] arrays",  aStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled]);
433     addInfo (theDict, "Rendered [point] arrays", aStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled]);
434     addInfo (theDict, "Rendered [text] arrays",  aStats[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled]);
435   }
436   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
437   {
438     addInfo (theDict, "Rendered triangles", aStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled]);
439   }
440   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
441   {
442     addInfo (theDict, "Rendered points", aStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled]);
443   }
444   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
445   {
446     addInfo (theDict, "GPU Memory [geometry]", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesGeom]);
447     addInfo (theDict, "GPU Memory [textures]", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesTextures]);
448     addInfo (theDict, "GPU Memory [frames]",   aStats[Graphic3d_FrameStatsCounter_EstimatedBytesFbos]);
449   }
450
451   if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
452   {
453     addTimeInfo (theDict, "Elapsed Frame (average)", aStats[Graphic3d_FrameStatsTimer_ElapsedFrame]);
454     addTimeInfo (theDict, "CPU Frame (average)",     aStats[Graphic3d_FrameStatsTimer_CpuFrame]);
455     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
456     {
457       addTimeInfo (theDict, "CPU Picking (average)", aStats[Graphic3d_FrameStatsTimer_CpuPicking]);
458     }
459     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
460     {
461       addTimeInfo (theDict, "CPU Culling (average)", aStats[Graphic3d_FrameStatsTimer_CpuCulling]);
462     }
463     if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
464     {
465       addTimeInfo (theDict, "CPU Dynamics (average)", aStats[Graphic3d_FrameStatsTimer_CpuDynamics]);
466     }
467     if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTimeMax) != 0)
468     {
469       addTimeInfo (theDict, "CPU Frame (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuFrame]);
470       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
471       {
472         addTimeInfo (theDict, "CPU Picking (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking]);
473       }
474       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
475       {
476         addTimeInfo (theDict, "CPU Culling (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling]);
477       }
478       if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
479       {
480         addTimeInfo (theDict, "CPU Dynamics (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics]);
481       }
482     }
483   }
484 }
485
486 // =======================================================================
487 // function : FrameStart
488 // purpose  :
489 // =======================================================================
490 void Graphic3d_FrameStats::FrameStart (const Handle(Graphic3d_CView)& theView,
491                                        bool theIsImmediateOnly)
492 {
493   const Graphic3d_RenderingParams::PerfCounters aBits = !theView.IsNull()
494                                                       ? theView->RenderingParams().CollectedStats
495                                                       : Graphic3d_RenderingParams::PerfCounters_NONE;
496   if (theIsImmediateOnly
497    && (aBits & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
498   {
499     return;
500   }
501
502   const Standard_Integer aNbFrames = Max (!theView.IsNull()
503                                          ? theView->RenderingParams().StatsNbFrames
504                                          : 1, 1);
505   if (myCounters.Size() != aNbFrames)
506   {
507     myCounters.Resize (0, aNbFrames - 1, false);
508     myCounters.Init (Graphic3d_FrameStatsData());
509     myLastFrameIndex = myCounters.Upper();
510   }
511
512   // reset values at the end of frame (after data has been flushed),
513   // so that application can put some counters (like picking time) before FrameStart().
514   //myCountersTmp.Reset();
515
516   myFrameStartTime = myFpsTimer.ElapsedTime();
517   if (!myFpsTimer.IsStarted())
518   {
519     myFpsTimer.Reset();
520     myFpsTimer.Start();
521     myFpsFrameCount = 0;
522   }
523 }
524
525 // =======================================================================
526 // function : FrameEnd
527 // purpose  :
528 // =======================================================================
529 void Graphic3d_FrameStats::FrameEnd (const Handle(Graphic3d_CView)& theView,
530                                      bool theIsImmediateOnly)
531 {
532   const Graphic3d_RenderingParams::PerfCounters aBits = !theView.IsNull()
533                                                       ? theView->RenderingParams().CollectedStats
534                                                       : Graphic3d_RenderingParams::PerfCounters_NONE;
535   if (theIsImmediateOnly
536    && (aBits & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
537   {
538     return;
539   }
540
541   const double aTime = myFpsTimer.ElapsedTime();
542   myFrameDuration = aTime - myFrameStartTime;
543   ++myFpsFrameCount;
544   if (!theView.IsNull())
545   {
546     myUpdateInterval = theView->RenderingParams().StatsUpdateInterval;
547   }
548
549   if (aTime < myUpdateInterval)
550   {
551     myCountersTmp.FlushTimers (myFpsFrameCount, false);
552     return;
553   }
554
555   if (aTime > gp::Resolution())
556   {
557     // update FPS
558     myFpsTimer.Stop();
559     const double aCpuSec = myFpsTimer.UserTimeCPU();
560
561     myCountersTmp[Graphic3d_FrameStatsTimer_ElapsedFrame]  = aTime;
562     myCountersTmp[Graphic3d_FrameStatsTimer_CpuFrame]      = aCpuSec;
563     myCountersTmp.ChangeFrameRate()    = double(myFpsFrameCount) / aTime;
564     myCountersTmp.ChangeFrameRateCpu() = aCpuSec > gp::Resolution()
565                                        ? double(myFpsFrameCount) / aCpuSec
566                                        : -1.0;
567     myCountersTmp.FlushTimers (myFpsFrameCount, true);
568     myCountersMax.FillMax (myCountersTmp);
569     myFpsTimer.Reset();
570     myFpsTimer.Start();
571     myFpsFrameCount = 0;
572   }
573
574   // update structure counters
575   if (theView.IsNull())
576   {
577     myCounters.SetValue (myLastFrameIndex, myCountersTmp);
578     myCountersTmp.Reset();
579     return;
580   }
581
582   updateStatistics (theView, theIsImmediateOnly);
583
584   if (++myLastFrameIndex > myCounters.Upper())
585   {
586     myLastFrameIndex = myCounters.Lower();
587   }
588   myCounters.SetValue (myLastFrameIndex, myCountersTmp);
589   myCountersTmp.Reset();
590 }