1 // Copyright (c) 2017 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
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.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #include <Graphic3d_FrameStats.hxx>
16 #include <Graphic3d_CView.hxx>
18 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_FrameStats, Standard_Transient)
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)
29 if (thePrefix != NULL)
31 theStream << thePrefix;
33 theStream << std::setfill(' ') << std::setw (theWidth);
34 if (theValue >= 1000000000)
36 Standard_Real aValM = Standard_Real(theValue) / 1000000000.0;
37 theStream << std::fixed << std::setprecision (1) << aValM << "G";
39 else if (theValue >= 1000000)
41 Standard_Real aValM = Standard_Real(theValue) / 1000000.0;
42 theStream << std::fixed << std::setprecision (1) << aValM << "M";
44 else if (theValue >= 1000)
46 Standard_Real aValK = Standard_Real(theValue) / 1000.0;
47 theStream << std::fixed << std::setprecision (1) << aValK << "k";
51 theStream << theValue;
53 if (thePostfix != NULL)
55 theStream << thePostfix;
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)
67 if (thePrefix != NULL)
69 theStream << thePrefix;
71 theStream << std::setfill(' ') << std::setw (theWidth);
72 if (theValue >= 1024 * 1024 * 1024)
74 Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0 * 1024.0);
75 theStream << std::fixed << std::setprecision (1) << aValM << " GiB";
77 else if (theValue >= 1024 * 1024)
79 Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0);
80 theStream << std::fixed << std::setprecision (1) << aValM << " MiB";
82 else if (theValue >= 1024)
84 Standard_Real aValK = Standard_Real(theValue) / 1024.0;
85 theStream << std::fixed << std::setprecision (1) << aValK << " KiB";
89 theStream << theValue << " B";
91 if (thePostfix != NULL)
93 theStream << thePostfix;
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;
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)
110 if (thePrefix != NULL)
112 theStream << thePrefix;
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;
125 theStream << std::setfill(' ') << std::setw (theWidth);
128 Sprintf (aBuffer, "%02u:%02u:%02u", aHours, aMinutes, aSeconds);
129 theStream << aBuffer;
131 else if (aMinutes > 0)
133 Sprintf (aBuffer, "%02u:%02u", aMinutes, aSeconds);
134 theStream << aBuffer;
136 else if (aSeconds > 0)
138 Sprintf (aBuffer, "%2u s", aSeconds);
139 theStream << aBuffer;
143 theStream << std::fixed << std::setprecision (1) << aMilliSeconds << " ms";
146 if (thePostfix != NULL)
148 theStream << thePostfix;
154 // =======================================================================
155 // function : Graphic3d_FrameStats
157 // =======================================================================
158 Graphic3d_FrameStats::Graphic3d_FrameStats()
159 : myFpsTimer (Standard_True),
160 myFrameStartTime (0.0),
161 myFrameDuration (0.0),
162 myUpdateInterval (1.0),
165 myLastFrameIndex (0),
166 myIsLongLineFormat (Standard_False)
171 // =======================================================================
172 // function : ~Graphic3d_FrameStats
174 // =======================================================================
175 Graphic3d_FrameStats::~Graphic3d_FrameStats()
180 // =======================================================================
181 // function : FormatStats
183 // =======================================================================
184 TCollection_AsciiString Graphic3d_FrameStats::FormatStats (Graphic3d_RenderingParams::PerfCounters theFlags) const
186 const Standard_Integer aValWidth = 5;
187 std::stringstream aBuf;
188 const Standard_Boolean isCompact = theFlags == Graphic3d_RenderingParams::PerfCounters_FrameRate; // only FPS is displayed
189 const Graphic3d_FrameStatsData& aStats = LastDataFrame();
190 if (myIsLongLineFormat
191 && (theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0
192 && (theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
194 aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 9) << std::fixed << std::setprecision (1) << aStats.FrameRate()
195 << " [CPU: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 10) << std::fixed << std::setprecision (1) << aStats.FrameRateCpu() << "]\n";
199 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
201 aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << aStats.FrameRate() << "\n";
203 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
205 aBuf << "CPU FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << aStats.FrameRateCpu() << "\n";
208 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
210 if (myIsLongLineFormat)
212 formatCounter (aBuf, aValWidth, "Layers: ", aStats[Graphic3d_FrameStatsCounter_NbLayers]);
213 if (HasCulledLayers())
215 formatCounter (aBuf, aValWidth, " [rendered: ", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled], "]");
221 formatCounter (aBuf, aValWidth + 3, "Layers: ", aStats[Graphic3d_FrameStatsCounter_NbLayers], "\n");
224 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
226 if (myIsLongLineFormat)
228 formatCounter (aBuf, aValWidth, "Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructs]);
229 if (HasCulledStructs())
231 formatCounter (aBuf, aValWidth, " [rendered: ", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled], "]");
237 formatCounter (aBuf, aValWidth + 3, "Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructs], "\n");
240 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0
241 || (theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0
242 || (theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
243 || (theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0
244 || (!myIsLongLineFormat
245 && ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
246 || (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)))
248 aBuf << "Rendered\n";
250 if (!myIsLongLineFormat
251 && (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
253 formatCounter (aBuf, aValWidth, " Layers: ", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled], "\n");
255 if (!myIsLongLineFormat
256 && (theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
258 formatCounter (aBuf, aValWidth, " Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled], "\n");
260 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
262 formatCounter (aBuf, aValWidth, " Groups: ", aStats[Graphic3d_FrameStatsCounter_NbGroupsNotCulled], "\n");
264 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
266 formatCounter (aBuf, aValWidth, " Arrays: ", aStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled], "\n");
267 formatCounter (aBuf, aValWidth, " [fill]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled], "\n");
268 formatCounter (aBuf, aValWidth, " [line]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled], "\n");
269 formatCounter (aBuf, aValWidth, " [point]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled], "\n");
270 formatCounter (aBuf, aValWidth, " [text]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled], "\n");
272 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
274 formatCounter (aBuf, aValWidth, " Triangles: ", aStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled], "\n");
276 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
278 formatCounter (aBuf, aValWidth, " Points: ", aStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled], "\n");
280 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
282 aBuf << "GPU Memory\n";
283 formatBytes (aBuf, aValWidth, " Geometry: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesGeom], "\n");
284 formatBytes (aBuf, aValWidth, " Textures: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesTextures], "\n");
285 formatBytes (aBuf, aValWidth, " Frames: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesFbos], "\n");
288 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
290 aBuf << "Timers Average\n";
291 formatTime (aBuf, aValWidth, " Elapsed Frame: ", aStats[Graphic3d_FrameStatsTimer_ElapsedFrame], "\n");
292 formatTime (aBuf, aValWidth, " CPU Frame: ", aStats[Graphic3d_FrameStatsTimer_CpuFrame], "\n");
293 if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
295 formatTime (aBuf, aValWidth, " CPU Picking: ", aStats[Graphic3d_FrameStatsTimer_CpuPicking], "\n");
297 if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
299 formatTime (aBuf, aValWidth, " CPU Culling: ", aStats[Graphic3d_FrameStatsTimer_CpuCulling], "\n");
301 if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
303 formatTime (aBuf, aValWidth, " CPU Dynamics: ", aStats[Graphic3d_FrameStatsTimer_CpuDynamics], "\n");
305 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTimeMax) != 0)
307 aBuf << "Timers Max\n";
308 formatTime (aBuf, aValWidth, " CPU Frame: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuFrame], "\n");
309 if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
311 formatTime (aBuf, aValWidth, " CPU Picking: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking], "\n");
313 if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
315 formatTime (aBuf, aValWidth, " CPU Culling: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling], "\n");
317 if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
319 formatTime (aBuf, aValWidth, " CPU Dynamics: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics], "\n");
324 return TCollection_AsciiString (aBuf.str().c_str());
327 // =======================================================================
328 // function : FrameStart
330 // =======================================================================
331 void Graphic3d_FrameStats::FrameStart (const Handle(Graphic3d_CView)& theView,
332 bool theIsImmediateOnly)
334 const Graphic3d_RenderingParams::PerfCounters aBits = !theView.IsNull()
335 ? theView->RenderingParams().CollectedStats
336 : Graphic3d_RenderingParams::PerfCounters_NONE;
337 if (theIsImmediateOnly
338 && (aBits & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
343 const Standard_Integer aNbFrames = Max (!theView.IsNull()
344 ? theView->RenderingParams().StatsNbFrames
346 if (myCounters.Size() != aNbFrames)
348 myCounters.Resize (0, aNbFrames - 1, false);
349 myCounters.Init (Graphic3d_FrameStatsData());
350 myLastFrameIndex = myCounters.Upper();
353 // reset values at the end of frame (after data has been flushed),
354 // so that application can put some counters (like picking time) before FrameStart().
355 //myCountersTmp.Reset();
357 myFrameStartTime = myFpsTimer.ElapsedTime();
358 if (!myFpsTimer.IsStarted())
366 // =======================================================================
367 // function : FrameEnd
369 // =======================================================================
370 void Graphic3d_FrameStats::FrameEnd (const Handle(Graphic3d_CView)& theView,
371 bool theIsImmediateOnly)
373 const Graphic3d_RenderingParams::PerfCounters aBits = !theView.IsNull()
374 ? theView->RenderingParams().CollectedStats
375 : Graphic3d_RenderingParams::PerfCounters_NONE;
376 if (theIsImmediateOnly
377 && (aBits & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
382 const double aTime = myFpsTimer.ElapsedTime();
383 myFrameDuration = aTime - myFrameStartTime;
385 if (!theView.IsNull())
387 myUpdateInterval = theView->RenderingParams().StatsUpdateInterval;
390 if (aTime < myUpdateInterval)
392 myCountersTmp.FlushTimers (myFpsFrameCount, false);
396 if (aTime > gp::Resolution())
400 const double aCpuSec = myFpsTimer.UserTimeCPU();
402 myCountersTmp[Graphic3d_FrameStatsTimer_ElapsedFrame] = aTime;
403 myCountersTmp[Graphic3d_FrameStatsTimer_CpuFrame] = aCpuSec;
404 myCountersTmp.ChangeFrameRate() = double(myFpsFrameCount) / aTime;
405 myCountersTmp.ChangeFrameRateCpu() = aCpuSec > gp::Resolution()
406 ? double(myFpsFrameCount) / aCpuSec
408 myCountersTmp.FlushTimers (myFpsFrameCount, true);
409 myCountersMax.FillMax (myCountersTmp);
415 // update structure counters
416 if (theView.IsNull())
418 myCounters.SetValue (myLastFrameIndex, myCountersTmp);
419 myCountersTmp.Reset();
423 updateStatistics (theView, theIsImmediateOnly);
425 if (++myLastFrameIndex > myCounters.Upper())
427 myLastFrameIndex = myCounters.Lower();
429 myCounters.SetValue (myLastFrameIndex, myCountersTmp);
430 myCountersTmp.Reset();