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 <OpenGl_FrameStats.hxx>
16 #include <OpenGl_GlCore20.hxx>
17 #include <OpenGl_View.hxx>
18 #include <OpenGl_Workspace.hxx>
20 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameStats, Standard_Transient)
25 static std::ostream& formatCounter (std::ostream& theStream,
26 Standard_Integer theWidth,
27 const char* thePrefix,
28 Standard_Size theValue,
29 const char* thePostfix = NULL)
31 if (thePrefix != NULL)
33 theStream << thePrefix;
35 theStream << std::setfill(' ') << std::setw (theWidth);
36 if (theValue >= 1000000000)
38 Standard_Real aValM = Standard_Real(theValue) / 1000000000.0;
39 theStream << std::fixed << std::setprecision (1) << aValM << "G";
41 else if (theValue >= 1000000)
43 Standard_Real aValM = Standard_Real(theValue) / 1000000.0;
44 theStream << std::fixed << std::setprecision (1) << aValM << "M";
46 else if (theValue >= 1000)
48 Standard_Real aValK = Standard_Real(theValue) / 1000.0;
49 theStream << std::fixed << std::setprecision (1) << aValK << "k";
53 theStream << theValue;
55 if (thePostfix != NULL)
57 theStream << thePostfix;
62 //! Format memory counter.
63 static std::ostream& formatBytes (std::ostream& theStream,
64 Standard_Integer theWidth,
65 const char* thePrefix,
66 Standard_Size theValue,
67 const char* thePostfix = NULL)
69 if (thePrefix != NULL)
71 theStream << thePrefix;
73 theStream << std::setfill(' ') << std::setw (theWidth);
74 if (theValue >= 1024 * 1024 * 1024)
76 Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0 * 1024.0);
77 theStream << std::fixed << std::setprecision (1) << aValM << " GiB";
79 else if (theValue >= 1024 * 1024)
81 Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0);
82 theStream << std::fixed << std::setprecision (1) << aValM << " MiB";
84 else if (theValue >= 1024)
86 Standard_Real aValK = Standard_Real(theValue) / 1024.0;
87 theStream << std::fixed << std::setprecision (1) << aValK << " KiB";
91 theStream << theValue;
93 if (thePostfix != NULL)
95 theStream << thePostfix;
100 //! Return estimated data size.
101 static Standard_Size estimatedDataSize (const Handle(OpenGl_Resource)& theRes)
103 return !theRes.IsNull() ? theRes->EstimatedDataSize() : 0;
107 // =======================================================================
108 // function : OpenGl_FrameStats
110 // =======================================================================
111 OpenGl_FrameStats::OpenGl_FrameStats()
112 : myFpsTimer (Standard_True),
113 myFrameStartTime (0.0),
114 myFrameDuration (0.0),
117 myUpdateInterval (1.0),
119 myIsLongLineFormat (Standard_False)
121 memset (myCounters, 0, sizeof(myCounters));
122 memset (myCountersTmp, 0, sizeof(myCountersTmp));
125 // =======================================================================
126 // function : ~OpenGl_FrameStats
128 // =======================================================================
129 OpenGl_FrameStats::~OpenGl_FrameStats()
134 // =======================================================================
135 // function : FormatStats
137 // =======================================================================
138 TCollection_AsciiString OpenGl_FrameStats::FormatStats (Graphic3d_RenderingParams::PerfCounters theFlags) const
140 const Standard_Integer aValWidth = 5;
141 std::stringstream aBuf;
142 const Standard_Boolean isCompact = theFlags == Graphic3d_RenderingParams::PerfCounters_FrameRate; // only FPS is displayed
143 if (myIsLongLineFormat
144 && (theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0
145 && (theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
147 aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 9) << std::fixed << std::setprecision (1) << myFps
148 << " [CPU: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 10) << std::fixed << std::setprecision (1) << myFpsCpu << "]\n";
152 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
154 aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << myFps << "\n";
156 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
158 aBuf << "CPU FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << myFpsCpu << "\n";
161 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
163 if (myIsLongLineFormat)
165 formatCounter (aBuf, aValWidth, "Layers: ", myCounters[Counter_NbLayers]);
166 if (HasCulledLayers())
168 formatCounter (aBuf, aValWidth, " [rendered: ", myCounters[Counter_NbLayersNotCulled], "]");
174 formatCounter (aBuf, aValWidth + 3, "Layers: ", myCounters[Counter_NbLayers], "\n");
177 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
179 if (myIsLongLineFormat)
181 formatCounter (aBuf, aValWidth, "Structs: ", myCounters[Counter_NbStructs]);
182 if (HasCulledStructs())
184 formatCounter (aBuf, aValWidth, " [rendered: ", myCounters[Counter_NbStructsNotCulled], "]");
190 formatCounter (aBuf, aValWidth + 3, "Structs: ", myCounters[Counter_NbStructs], "\n");
193 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0
194 || (theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0
195 || (theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
196 || (theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0
197 || (!myIsLongLineFormat
198 && ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
199 || (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)))
201 aBuf << "Rendered\n";
203 if (!myIsLongLineFormat
204 && (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
206 formatCounter (aBuf, aValWidth, " Layers: ", myCounters[Counter_NbLayersNotCulled], "\n");
208 if (!myIsLongLineFormat
209 && (theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
211 formatCounter (aBuf, aValWidth, " Structs: ", myCounters[Counter_NbStructsNotCulled], "\n");
213 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
215 formatCounter (aBuf, aValWidth, " Groups: ", myCounters[Counter_NbGroupsNotCulled], "\n");
217 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
219 formatCounter (aBuf, aValWidth, " Arrays: ", myCounters[Counter_NbElemsNotCulled], "\n");
220 formatCounter (aBuf, aValWidth, " [fill]: ", myCounters[Counter_NbElemsFillNotCulled], "\n");
221 formatCounter (aBuf, aValWidth, " [line]: ", myCounters[Counter_NbElemsLineNotCulled], "\n");
222 formatCounter (aBuf, aValWidth, " [point]: ", myCounters[Counter_NbElemsPointNotCulled], "\n");
223 formatCounter (aBuf, aValWidth, " [text]: ", myCounters[Counter_NbElemsTextNotCulled], "\n");
225 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
227 formatCounter (aBuf, aValWidth, " Triangles: ", myCounters[Counter_NbTrianglesNotCulled], "\n");
229 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
231 formatCounter (aBuf, aValWidth, " Points: ", myCounters[Counter_NbPointsNotCulled], "\n");
233 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
235 aBuf << "GPU Memory\n";
236 formatBytes (aBuf, aValWidth, " Geometry: ", myCounters[Counter_EstimatedBytesGeom], "\n");
237 formatBytes (aBuf, aValWidth, " Textures: ", myCounters[Counter_EstimatedBytesTextures], "\n");
238 formatBytes (aBuf, aValWidth, " Frames: ", myCounters[Counter_EstimatedBytesFbos], "\n");
240 return TCollection_AsciiString (aBuf.str().c_str());
243 // =======================================================================
244 // function : FrameStart
246 // =======================================================================
247 void OpenGl_FrameStats::FrameStart (const Handle(OpenGl_Workspace)& )
249 memset (myCountersTmp, 0, sizeof(myCountersTmp));
250 myFrameStartTime = myFpsTimer.ElapsedTime();
251 if (!myFpsTimer.IsStarted())
259 // =======================================================================
260 // function : FrameEnd
262 // =======================================================================
263 void OpenGl_FrameStats::FrameEnd (const Handle(OpenGl_Workspace)& theWorkspace)
265 const Graphic3d_RenderingParams::PerfCounters aBits = !theWorkspace.IsNull()
266 ? theWorkspace->View()->RenderingParams().CollectedStats
267 : Graphic3d_RenderingParams::PerfCounters_NONE;
268 const double aTime = myFpsTimer.ElapsedTime();
269 myFrameDuration = aTime - myFrameStartTime;
271 if (!theWorkspace.IsNull())
273 myUpdateInterval = theWorkspace->View()->RenderingParams().StatsUpdateInterval;
276 if (aTime < myUpdateInterval)
281 if (aTime > gp::Resolution())
285 const double aCpuSec = myFpsTimer.UserTimeCPU();
286 myFps = double(myFpsFrameCount) / aTime;
287 myFpsCpu = aCpuSec > gp::Resolution()
288 ? double(myFpsFrameCount) / aCpuSec
295 // update structure counters
296 if (theWorkspace.IsNull())
298 memcpy (myCounters, myCountersTmp, sizeof(myCounters));
302 const Standard_Boolean toCountMem = (aBits & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0;
303 const Standard_Boolean toCountTris = (aBits & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
304 || (aBits & Graphic3d_RenderingParams::PerfCounters_Points) != 0;
305 const Standard_Boolean toCountElems = (aBits & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0 || toCountTris || toCountMem;
306 const Standard_Boolean toCountGroups = (aBits & Graphic3d_RenderingParams::PerfCounters_Groups) != 0 || toCountElems;
307 const Standard_Boolean toCountStructs = (aBits & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
308 || (aBits & Graphic3d_RenderingParams::PerfCounters_Layers) != 0 || toCountGroups;
310 myCountersTmp[Counter_NbLayers] = theWorkspace->View()->LayerList().Layers().Size();
312 || (aBits & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
314 const Standard_Integer aViewId = theWorkspace->View()->Identification();
315 for (OpenGl_SequenceOfLayers::Iterator aLayerIter (theWorkspace->View()->LayerList().Layers()); aLayerIter.More(); aLayerIter.Next())
317 const Handle(OpenGl_Layer)& aLayer = aLayerIter.Value();
318 if (!aLayer->IsCulled())
320 ++myCountersTmp[Counter_NbLayersNotCulled];
322 myCountersTmp[Counter_NbStructs] += aLayer->NbStructures();
323 myCountersTmp[Counter_NbStructsNotCulled] += aLayer->NbStructuresNotCulled();
326 updateStructures (aViewId, aLayer->CullableStructuresBVH().Structures(), toCountElems, toCountTris, toCountMem);
327 updateStructures (aViewId, aLayer->CullableTrsfPersStructuresBVH().Structures(), toCountElems, toCountTris, toCountMem);
328 updateStructures (aViewId, aLayer->NonCullableStructures(), toCountElems, toCountTris, toCountMem);
333 && !theWorkspace.IsNull())
335 for (OpenGl_Context::OpenGl_ResourcesMap::Iterator aResIter (theWorkspace->GetGlContext()->SharedResources());
336 aResIter.More(); aResIter.Next())
338 myCountersTmp[Counter_EstimatedBytesTextures] += aResIter.Value()->EstimatedDataSize();
341 const OpenGl_View* aView = theWorkspace->View();
343 Standard_Size& aMemFbos = myCountersTmp[Counter_EstimatedBytesFbos];
345 aMemFbos += estimatedDataSize (aView->myMainSceneFbos[0]);
346 aMemFbos += estimatedDataSize (aView->myMainSceneFbos[1]);
347 aMemFbos += estimatedDataSize (aView->myImmediateSceneFbos[0]);
348 aMemFbos += estimatedDataSize (aView->myImmediateSceneFbos[1]);
350 aMemFbos += estimatedDataSize (aView->myMainSceneFbosOit[0]);
351 aMemFbos += estimatedDataSize (aView->myMainSceneFbosOit[1]);
352 aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[0]);
353 aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[1]);
355 aMemFbos += estimatedDataSize (aView->myFBO);
357 aMemFbos += estimatedDataSize (aView->myOpenGlFBO);
358 aMemFbos += estimatedDataSize (aView->myOpenGlFBO2);
359 aMemFbos += estimatedDataSize (aView->myRaytraceFBO1[0]);
360 aMemFbos += estimatedDataSize (aView->myRaytraceFBO1[1]);
361 aMemFbos += estimatedDataSize (aView->myRaytraceFBO2[0]);
362 aMemFbos += estimatedDataSize (aView->myRaytraceFBO2[1]);
364 aMemFbos += estimatedDataSize (aView->myRaytraceOutputTexture[0]);
365 aMemFbos += estimatedDataSize (aView->myRaytraceOutputTexture[1]);
366 aMemFbos += estimatedDataSize (aView->myRaytraceVisualErrorTexture[0]);
367 aMemFbos += estimatedDataSize (aView->myRaytraceVisualErrorTexture[1]);
368 aMemFbos += estimatedDataSize (aView->myRaytraceTileOffsetsTexture[0]);
369 aMemFbos += estimatedDataSize (aView->myRaytraceTileOffsetsTexture[1]);
372 // Ray Tracing geometry
373 Standard_Size& aMemGeom = myCountersTmp[Counter_EstimatedBytesGeom];
374 aMemGeom += estimatedDataSize (aView->mySceneNodeInfoTexture);
375 aMemGeom += estimatedDataSize (aView->mySceneMinPointTexture);
376 aMemGeom += estimatedDataSize (aView->mySceneMaxPointTexture);
377 aMemGeom += estimatedDataSize (aView->mySceneTransformTexture);
378 aMemGeom += estimatedDataSize (aView->myGeometryVertexTexture);
379 aMemGeom += estimatedDataSize (aView->myGeometryNormalTexture);
380 aMemGeom += estimatedDataSize (aView->myGeometryTexCrdTexture);
381 aMemGeom += estimatedDataSize (aView->myGeometryTriangTexture);
382 aMemGeom += estimatedDataSize (aView->myRaytraceMaterialTexture);
383 aMemGeom += estimatedDataSize (aView->myRaytraceLightSrcTexture);
386 memcpy (myCounters, myCountersTmp, sizeof(myCounters));
389 // =======================================================================
390 // function : updateStructures
392 // =======================================================================
393 void OpenGl_FrameStats::updateStructures (Standard_Integer theViewId,
394 const OpenGl_IndexedMapOfStructure& theStructures,
395 Standard_Boolean theToCountElems,
396 Standard_Boolean theToCountTris,
397 Standard_Boolean theToCountMem)
399 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (theStructures); aStructIter.More(); aStructIter.Next())
401 const OpenGl_Structure* aStruct = aStructIter.Value();
402 if (aStruct->IsCulled()
403 || !aStruct->IsVisible (theViewId))
407 for (OpenGl_Structure::GroupIterator aGroupIter (aStruct->Groups()); aGroupIter.More(); aGroupIter.Next())
409 const OpenGl_Group* aGroup = aGroupIter.Value();
410 for (const OpenGl_ElementNode* aNodeIter = aGroup->FirstNode(); aNodeIter != NULL; aNodeIter = aNodeIter->next)
412 if (const OpenGl_PrimitiveArray* aPrim = dynamic_cast<const OpenGl_PrimitiveArray*> (aNodeIter->elem))
414 myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
415 myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
423 myCountersTmp[Counter_NbGroupsNotCulled] += aStruct->Groups().Size();
424 if (!theToCountElems)
429 for (OpenGl_Structure::GroupIterator aGroupIter (aStruct->Groups()); aGroupIter.More(); aGroupIter.Next())
431 const OpenGl_Group* aGroup = aGroupIter.Value();
432 for (const OpenGl_ElementNode* aNodeIter = aGroup->FirstNode(); aNodeIter != NULL; aNodeIter = aNodeIter->next)
434 if (const OpenGl_PrimitiveArray* aPrim = dynamic_cast<const OpenGl_PrimitiveArray*> (aNodeIter->elem))
436 ++myCountersTmp[Counter_NbElemsNotCulled];
439 myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
440 myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
443 if (aPrim->IsFillDrawMode())
445 ++myCountersTmp[Counter_NbElemsFillNotCulled];
451 const Handle(OpenGl_VertexBuffer)& anAttribs = aPrim->AttributesVbo();
452 if (anAttribs.IsNull()
453 || !anAttribs->IsValid())
458 const Handle(OpenGl_VertexBuffer)& anIndices = aPrim->IndexVbo();
459 const Standard_Integer aNbIndices = !anIndices.IsNull() ? anIndices->GetElemsNb() : anAttribs->GetElemsNb();
460 const Standard_Integer aNbBounds = !aPrim->Bounds().IsNull() ? aPrim->Bounds()->NbBounds : 1;
461 switch (aPrim->DrawMode())
465 myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 3;
468 case GL_TRIANGLE_STRIP:
469 case GL_TRIANGLE_FAN:
471 myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices - 2 * aNbBounds;
474 case GL_TRIANGLES_ADJACENCY:
476 myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 6;
479 case GL_TRIANGLE_STRIP_ADJACENCY:
481 myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices - 4 * aNbBounds;
484 #if !defined(GL_ES_VERSION_2_0)
487 myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 2;
492 myCountersTmp[Counter_NbTrianglesNotCulled] += (aNbIndices / 2 - aNbBounds) * 2;
498 else if (aPrim->DrawMode() == GL_POINTS)
500 ++myCountersTmp[Counter_NbElemsPointNotCulled];
503 const Handle(OpenGl_VertexBuffer)& anAttribs = aPrim->AttributesVbo();
504 if (!anAttribs.IsNull()
505 && anAttribs->IsValid())
507 const Handle(OpenGl_VertexBuffer)& anIndices = aPrim->IndexVbo();
508 const Standard_Integer aNbIndices = !anIndices.IsNull() ? anIndices->GetElemsNb() : anAttribs->GetElemsNb();
509 myCountersTmp[Counter_NbPointsNotCulled] += aNbIndices;
515 ++myCountersTmp[Counter_NbElemsLineNotCulled];
518 else if (const OpenGl_Text* aText = dynamic_cast<const OpenGl_Text*> (aNodeIter->elem))
521 ++myCountersTmp[Counter_NbElemsNotCulled];
522 ++myCountersTmp[Counter_NbElemsTextNotCulled];