1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-05 18:16:23 +03:00

0030144: Visualization, TKOpenGl - extend OpenGl_FrameStats with frame timers

This commit is contained in:
kgv 2018-09-17 18:11:05 +03:00 committed by apn
parent 9b9f2fe972
commit 5e30547b63
18 changed files with 1391 additions and 438 deletions

View File

@ -43,6 +43,12 @@ Graphic3d_CView.hxx
Graphic3d_DataStructureManager.cxx
Graphic3d_DataStructureManager.hxx
Graphic3d_DiagnosticInfo.hxx
Graphic3d_FrameStats.cxx
Graphic3d_FrameStats.hxx
Graphic3d_FrameStatsCounter.hxx
Graphic3d_FrameStatsData.cxx
Graphic3d_FrameStatsData.hxx
Graphic3d_FrameStatsTimer.hxx
Graphic3d_GraduatedTrihedron.hxx
Graphic3d_GraphicDriver.cxx
Graphic3d_GraphicDriver.hxx

View File

@ -0,0 +1,431 @@
// Copyright (c) 2017 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Graphic3d_FrameStats.hxx>
#include <Graphic3d_CView.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_FrameStats, Standard_Transient)
namespace
{
//! Format counter.
static std::ostream& formatCounter (std::ostream& theStream,
Standard_Integer theWidth,
const char* thePrefix,
Standard_Size theValue,
const char* thePostfix = NULL)
{
if (thePrefix != NULL)
{
theStream << thePrefix;
}
theStream << std::setfill(' ') << std::setw (theWidth);
if (theValue >= 1000000000)
{
Standard_Real aValM = Standard_Real(theValue) / 1000000000.0;
theStream << std::fixed << std::setprecision (1) << aValM << "G";
}
else if (theValue >= 1000000)
{
Standard_Real aValM = Standard_Real(theValue) / 1000000.0;
theStream << std::fixed << std::setprecision (1) << aValM << "M";
}
else if (theValue >= 1000)
{
Standard_Real aValK = Standard_Real(theValue) / 1000.0;
theStream << std::fixed << std::setprecision (1) << aValK << "k";
}
else
{
theStream << theValue;
}
if (thePostfix != NULL)
{
theStream << thePostfix;
}
return theStream;
}
//! Format memory counter.
static std::ostream& formatBytes (std::ostream& theStream,
Standard_Integer theWidth,
const char* thePrefix,
Standard_Size theValue,
const char* thePostfix = NULL)
{
if (thePrefix != NULL)
{
theStream << thePrefix;
}
theStream << std::setfill(' ') << std::setw (theWidth);
if (theValue >= 1024 * 1024 * 1024)
{
Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0 * 1024.0);
theStream << std::fixed << std::setprecision (1) << aValM << " GiB";
}
else if (theValue >= 1024 * 1024)
{
Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0);
theStream << std::fixed << std::setprecision (1) << aValM << " MiB";
}
else if (theValue >= 1024)
{
Standard_Real aValK = Standard_Real(theValue) / 1024.0;
theStream << std::fixed << std::setprecision (1) << aValK << " KiB";
}
else
{
theStream << theValue << " B";
}
if (thePostfix != NULL)
{
theStream << thePostfix;
}
return theStream;
}
static const Standard_Real THE_SECONDS_IN_HOUR = 3600.0;
static const Standard_Real THE_SECONDS_IN_MINUTE = 60.0;
static const Standard_Real THE_SECOND_IN_HOUR = 1.0 / THE_SECONDS_IN_HOUR;
static const Standard_Real THE_SECOND_IN_MINUTE = 1.0 / THE_SECONDS_IN_MINUTE;
//! Format time.
static std::ostream& formatTime (std::ostream& theStream,
Standard_Integer theWidth,
const char* thePrefix,
Standard_Real theSeconds,
const char* thePostfix = NULL)
{
if (thePrefix != NULL)
{
theStream << thePrefix;
}
Standard_Real aSecIn = theSeconds;
unsigned int aHours = (unsigned int )(aSecIn * THE_SECOND_IN_HOUR);
aSecIn -= Standard_Real(aHours) * THE_SECONDS_IN_HOUR;
unsigned int aMinutes = (unsigned int )(aSecIn * THE_SECOND_IN_MINUTE);
aSecIn -= Standard_Real(aMinutes) * THE_SECONDS_IN_MINUTE;
unsigned int aSeconds = (unsigned int )aSecIn;
aSecIn -= Standard_Real(aSeconds);
Standard_Real aMilliSeconds = 1000.0 * aSecIn;
char aBuffer[64];
theStream << std::setfill(' ') << std::setw (theWidth);
if (aHours > 0)
{
Sprintf (aBuffer, "%02u:%02u:%02u", aHours, aMinutes, aSeconds);
theStream << aBuffer;
}
else if (aMinutes > 0)
{
Sprintf (aBuffer, "%02u:%02u", aMinutes, aSeconds);
theStream << aBuffer;
}
else if (aSeconds > 0)
{
Sprintf (aBuffer, "%2u s", aSeconds);
theStream << aBuffer;
}
else
{
theStream << std::fixed << std::setprecision (1) << aMilliSeconds << " ms";
}
if (thePostfix != NULL)
{
theStream << thePostfix;
}
return theStream;
}
}
// =======================================================================
// function : Graphic3d_FrameStats
// purpose :
// =======================================================================
Graphic3d_FrameStats::Graphic3d_FrameStats()
: myFpsTimer (Standard_True),
myFrameStartTime (0.0),
myFrameDuration (0.0),
myUpdateInterval (1.0),
myFpsFrameCount (0),
myCounters (0, 0),
myLastFrameIndex (0),
myIsLongLineFormat (Standard_False)
{
//
}
// =======================================================================
// function : ~Graphic3d_FrameStats
// purpose :
// =======================================================================
Graphic3d_FrameStats::~Graphic3d_FrameStats()
{
//
}
// =======================================================================
// function : FormatStats
// purpose :
// =======================================================================
TCollection_AsciiString Graphic3d_FrameStats::FormatStats (Graphic3d_RenderingParams::PerfCounters theFlags) const
{
const Standard_Integer aValWidth = 5;
std::stringstream aBuf;
const Standard_Boolean isCompact = theFlags == Graphic3d_RenderingParams::PerfCounters_FrameRate; // only FPS is displayed
const Graphic3d_FrameStatsData& aStats = LastDataFrame();
if (myIsLongLineFormat
&& (theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0
&& (theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
{
aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 9) << std::fixed << std::setprecision (1) << aStats.FrameRate()
<< " [CPU: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 10) << std::fixed << std::setprecision (1) << aStats.FrameRateCpu() << "]\n";
}
else
{
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
{
aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << aStats.FrameRate() << "\n";
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
{
aBuf << "CPU FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << aStats.FrameRateCpu() << "\n";
}
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
{
if (myIsLongLineFormat)
{
formatCounter (aBuf, aValWidth, "Layers: ", aStats[Graphic3d_FrameStatsCounter_NbLayers]);
if (HasCulledLayers())
{
formatCounter (aBuf, aValWidth, " [rendered: ", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled], "]");
}
aBuf << "\n";
}
else
{
formatCounter (aBuf, aValWidth + 3, "Layers: ", aStats[Graphic3d_FrameStatsCounter_NbLayers], "\n");
}
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
{
if (myIsLongLineFormat)
{
formatCounter (aBuf, aValWidth, "Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructs]);
if (HasCulledStructs())
{
formatCounter (aBuf, aValWidth, " [rendered: ", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled], "]");
}
aBuf << "\n";
}
else
{
formatCounter (aBuf, aValWidth + 3, "Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructs], "\n");
}
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0
|| (!myIsLongLineFormat
&& ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)))
{
aBuf << "Rendered\n";
}
if (!myIsLongLineFormat
&& (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
{
formatCounter (aBuf, aValWidth, " Layers: ", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled], "\n");
}
if (!myIsLongLineFormat
&& (theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
{
formatCounter (aBuf, aValWidth, " Structs: ", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
{
formatCounter (aBuf, aValWidth, " Groups: ", aStats[Graphic3d_FrameStatsCounter_NbGroupsNotCulled], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
{
formatCounter (aBuf, aValWidth, " Arrays: ", aStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled], "\n");
formatCounter (aBuf, aValWidth, " [fill]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled], "\n");
formatCounter (aBuf, aValWidth, " [line]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled], "\n");
formatCounter (aBuf, aValWidth, " [point]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled], "\n");
formatCounter (aBuf, aValWidth, " [text]: ", aStats[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
{
formatCounter (aBuf, aValWidth, " Triangles: ", aStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
{
formatCounter (aBuf, aValWidth, " Points: ", aStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
{
aBuf << "GPU Memory\n";
formatBytes (aBuf, aValWidth, " Geometry: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesGeom], "\n");
formatBytes (aBuf, aValWidth, " Textures: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesTextures], "\n");
formatBytes (aBuf, aValWidth, " Frames: ", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesFbos], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
{
aBuf << "Timers Average\n";
formatTime (aBuf, aValWidth, " Elapsed Frame: ", aStats[Graphic3d_FrameStatsTimer_ElapsedFrame], "\n");
formatTime (aBuf, aValWidth, " CPU Frame: ", aStats[Graphic3d_FrameStatsTimer_CpuFrame], "\n");
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
{
formatTime (aBuf, aValWidth, " CPU Picking: ", aStats[Graphic3d_FrameStatsTimer_CpuPicking], "\n");
}
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
{
formatTime (aBuf, aValWidth, " CPU Culling: ", aStats[Graphic3d_FrameStatsTimer_CpuCulling], "\n");
}
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
{
formatTime (aBuf, aValWidth, " CPU Dynamics: ", aStats[Graphic3d_FrameStatsTimer_CpuDynamics], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTimeMax) != 0)
{
aBuf << "Timers Max\n";
formatTime (aBuf, aValWidth, " CPU Frame: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuFrame], "\n");
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
{
formatTime (aBuf, aValWidth, " CPU Picking: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking], "\n");
}
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
{
formatTime (aBuf, aValWidth, " CPU Culling: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling], "\n");
}
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
{
formatTime (aBuf, aValWidth, " CPU Dynamics: ", myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics], "\n");
}
}
}
return TCollection_AsciiString (aBuf.str().c_str());
}
// =======================================================================
// function : FrameStart
// purpose :
// =======================================================================
void Graphic3d_FrameStats::FrameStart (const Handle(Graphic3d_CView)& theView,
bool theIsImmediateOnly)
{
const Graphic3d_RenderingParams::PerfCounters aBits = !theView.IsNull()
? theView->RenderingParams().CollectedStats
: Graphic3d_RenderingParams::PerfCounters_NONE;
if (theIsImmediateOnly
&& (aBits & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
{
return;
}
const Standard_Integer aNbFrames = Max (!theView.IsNull()
? theView->RenderingParams().StatsNbFrames
: 1, 1);
if (myCounters.Size() != aNbFrames)
{
myCounters.Resize (0, aNbFrames - 1, false);
myCounters.Init (Graphic3d_FrameStatsData());
myLastFrameIndex = myCounters.Upper();
}
// reset values at the end of frame (after data has been flushed),
// so that application can put some counters (like picking time) before FrameStart().
//myCountersTmp.Reset();
myFrameStartTime = myFpsTimer.ElapsedTime();
if (!myFpsTimer.IsStarted())
{
myFpsTimer.Reset();
myFpsTimer.Start();
myFpsFrameCount = 0;
}
}
// =======================================================================
// function : FrameEnd
// purpose :
// =======================================================================
void Graphic3d_FrameStats::FrameEnd (const Handle(Graphic3d_CView)& theView,
bool theIsImmediateOnly)
{
const Graphic3d_RenderingParams::PerfCounters aBits = !theView.IsNull()
? theView->RenderingParams().CollectedStats
: Graphic3d_RenderingParams::PerfCounters_NONE;
if (theIsImmediateOnly
&& (aBits & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
{
return;
}
const double aTime = myFpsTimer.ElapsedTime();
myFrameDuration = aTime - myFrameStartTime;
++myFpsFrameCount;
if (!theView.IsNull())
{
myUpdateInterval = theView->RenderingParams().StatsUpdateInterval;
}
if (aTime < myUpdateInterval)
{
myCountersTmp.FlushTimers (myFpsFrameCount, false);
return;
}
if (aTime > gp::Resolution())
{
// update FPS
myFpsTimer.Stop();
const double aCpuSec = myFpsTimer.UserTimeCPU();
myCountersTmp[Graphic3d_FrameStatsTimer_ElapsedFrame] = aTime;
myCountersTmp[Graphic3d_FrameStatsTimer_CpuFrame] = aCpuSec;
myCountersTmp.ChangeFrameRate() = double(myFpsFrameCount) / aTime;
myCountersTmp.ChangeFrameRateCpu() = aCpuSec > gp::Resolution()
? double(myFpsFrameCount) / aCpuSec
: -1.0;
myCountersTmp.FlushTimers (myFpsFrameCount, true);
myCountersMax.FillMax (myCountersTmp);
myFpsTimer.Reset();
myFpsTimer.Start();
myFpsFrameCount = 0;
}
// update structure counters
if (theView.IsNull())
{
myCounters.SetValue (myLastFrameIndex, myCountersTmp);
myCountersTmp.Reset();
return;
}
updateStatistics (theView, theIsImmediateOnly);
if (++myLastFrameIndex > myCounters.Upper())
{
myLastFrameIndex = myCounters.Lower();
}
myCounters.SetValue (myLastFrameIndex, myCountersTmp);
myCountersTmp.Reset();
}

View File

@ -0,0 +1,136 @@
// Copyright (c) 2017 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _Graphic3d_FrameStats_HeaderFile
#define _Graphic3d_FrameStats_HeaderFile
#include <Graphic3d_FrameStatsData.hxx>
#include <Graphic3d_RenderingParams.hxx>
#include <Standard_Type.hxx>
#include <Standard_Transient.hxx>
class Graphic3d_CView;
//! Class storing the frame statistics.
class Graphic3d_FrameStats : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Graphic3d_FrameStats, Standard_Transient)
public:
//! Default constructor.
Standard_EXPORT Graphic3d_FrameStats();
//! Destructor.
Standard_EXPORT virtual ~Graphic3d_FrameStats();
//! Returns interval in seconds for updating meters across several frames; 1 second by default.
Standard_Real UpdateInterval() const { return myUpdateInterval; }
//! Sets interval in seconds for updating values.
void SetUpdateInterval (Standard_Real theInterval) { myUpdateInterval = theInterval; }
//! Prefer longer lines over more greater of lines.
Standard_Boolean IsLongLineFormat() const { return myIsLongLineFormat; }
//! Set if format should prefer longer lines over greater number of lines.
void SetLongLineFormat (Standard_Boolean theValue) { myIsLongLineFormat = theValue; }
//! Frame redraw started.
Standard_EXPORT virtual void FrameStart (const Handle(Graphic3d_CView)& theView,
bool theIsImmediateOnly);
//! Frame redraw finished.
Standard_EXPORT virtual void FrameEnd (const Handle(Graphic3d_CView)& theView,
bool theIsImmediateOnly);
public:
//! Returns formatted string.
Standard_EXPORT virtual TCollection_AsciiString FormatStats (Graphic3d_RenderingParams::PerfCounters theFlags) const;
//! Returns duration of the last frame in seconds.
Standard_Real FrameDuration() const { return myFrameDuration; }
//! Returns FPS (frames per seconds, elapsed time).
//! This number indicates an actual frame rate averaged for several frames within UpdateInterval() duration,
//! basing on a real elapsed time between updates.
Standard_Real FrameRate() const { return LastDataFrame().FrameRate(); }
//! Returns CPU FPS (frames per seconds, CPU time).
//! This number indicates a PREDICTED frame rate,
//! basing on CPU elapsed time between updates and NOT real elapsed time (which might include periods of CPU inactivity).
//! Number is expected to be greater then actual frame rate returned by FrameRate().
//! Values significantly greater actual frame rate indicate that rendering is limited by GPU performance (CPU is stalled in-between),
//! while values around actual frame rate indicate rendering being limited by CPU performance (GPU is stalled in-between).
Standard_Real FrameRateCpu() const { return LastDataFrame().FrameRateCpu(); }
//! Returns value of specified counter, cached between stats updates.
//! Should NOT be called between ::FrameStart() and ::FrameEnd() calls.
Standard_Size CounterValue (Graphic3d_FrameStatsCounter theCounter) const { return LastDataFrame()[theCounter]; }
//! Returns value of specified timer for modification, should be called between ::FrameStart() and ::FrameEnd() calls.
//! Should NOT be called between ::FrameStart() and ::FrameEnd() calls.
Standard_Real TimerValue (Graphic3d_FrameStatsTimer theTimer) const { return LastDataFrame()[theTimer]; }
//! Returns TRUE if some Layers have been culled.
Standard_Boolean HasCulledLayers() const { return LastDataFrame()[Graphic3d_FrameStatsCounter_NbLayersNotCulled] != LastDataFrame()[Graphic3d_FrameStatsCounter_NbLayers]; }
//! Returns TRUE if some structures have been culled.
Standard_Boolean HasCulledStructs() const { return LastDataFrame()[Graphic3d_FrameStatsCounter_NbStructsNotCulled] != LastDataFrame()[Graphic3d_FrameStatsCounter_NbStructs]; }
//! Returns last data frame, cached between stats updates.
//! Should NOT be called between ::FrameStart() and ::FrameEnd() calls.
const Graphic3d_FrameStatsData& LastDataFrame() const { return myCounters.Value (myLastFrameIndex); }
//! Returns last data frame index.
Standard_Integer LastDataFrameIndex() const { return myLastFrameIndex; }
//! Returns data frames.
const NCollection_Array1<Graphic3d_FrameStatsData>& DataFrames() const { return myCounters; }
//! Returns data frames.
NCollection_Array1<Graphic3d_FrameStatsData>& ChangeDataFrames() { return myCounters; }
public:
//! Returns value of specified counter for modification, should be called between ::FrameStart() and ::FrameEnd() calls.
Standard_Size& ChangeCounter (Graphic3d_FrameStatsCounter theCounter) { return ActiveDataFrame()[theCounter]; }
//! Returns value of specified timer for modification, should be called between ::FrameStart() and ::FrameEnd() calls.
Standard_Real& ChangeTimer (Graphic3d_FrameStatsTimer theTimer) { return ActiveDataFrame()[theTimer]; }
//! Returns currently filling data frame for modification, should be called between ::FrameStart() and ::FrameEnd() calls.
Graphic3d_FrameStatsDataTmp& ActiveDataFrame() { return myCountersTmp; }
protected:
//! Method to collect statistics from the View; called by FrameEnd().
virtual void updateStatistics (const Handle(Graphic3d_CView)& theView,
bool theIsImmediateOnly) = 0;
protected:
OSD_Timer myFpsTimer; //!< timer for FPS measurements
Standard_Real myFrameStartTime; //!< time at the beginning of frame redraw
Standard_Real myFrameDuration; //!< frame duration
Standard_Real myUpdateInterval; //!< interval to update meters
Standard_Size myFpsFrameCount; //!< FPS counter (within short measurement time slice)
NCollection_Array1<Graphic3d_FrameStatsData> myCounters; //!< data frames history
Graphic3d_FrameStatsDataTmp myCountersTmp; //!< data frame values filled to be filled between FrameStart() and FrameEnd() calls
Graphic3d_FrameStatsData myCountersMax; //!< data frame values with absolute maximum values in the history
Standard_Integer myLastFrameIndex; //!< last data frame index
Standard_Boolean myIsLongLineFormat; //!< prefer longer lines over greater number of lines
};
#endif // _Graphic3d_FrameStats_HeaderFile

View File

@ -0,0 +1,38 @@
// Copyright (c) 2018 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _Graphic3d_FrameStatsCounter_HeaderFile
#define _Graphic3d_FrameStatsCounter_HeaderFile
//! Stats counter.
enum Graphic3d_FrameStatsCounter
{
Graphic3d_FrameStatsCounter_NbLayers = 0, //!< number of ZLayers
Graphic3d_FrameStatsCounter_NbLayersNotCulled, //!< number of not culled ZLayers
Graphic3d_FrameStatsCounter_NbStructs, //!< number of defined OpenGl_Structure
Graphic3d_FrameStatsCounter_NbStructsNotCulled, //!< number of not culled OpenGl_Structure
Graphic3d_FrameStatsCounter_NbGroupsNotCulled, //!< number of not culled OpenGl_Group
Graphic3d_FrameStatsCounter_NbElemsNotCulled, //!< number of not culled OpenGl_Element
Graphic3d_FrameStatsCounter_NbElemsFillNotCulled, //!< number of not culled OpenGl_PrimitiveArray drawing triangles
Graphic3d_FrameStatsCounter_NbElemsLineNotCulled, //!< number of not culled OpenGl_PrimitiveArray drawing lines
Graphic3d_FrameStatsCounter_NbElemsPointNotCulled, //!< number of not culled OpenGl_PrimitiveArray drawing points
Graphic3d_FrameStatsCounter_NbElemsTextNotCulled, //!< number of not culled OpenGl_Text
Graphic3d_FrameStatsCounter_NbTrianglesNotCulled, //!< number of not culled (as structure) triangles
Graphic3d_FrameStatsCounter_NbPointsNotCulled, //!< number of not culled (as structure) points
Graphic3d_FrameStatsCounter_EstimatedBytesGeom, //!< estimated GPU memory used for geometry
Graphic3d_FrameStatsCounter_EstimatedBytesFbos, //!< estimated GPU memory used for FBOs
Graphic3d_FrameStatsCounter_EstimatedBytesTextures, //!< estimated GPU memory used for textures
};
enum { Graphic3d_FrameStatsCounter_NB = Graphic3d_FrameStatsCounter_EstimatedBytesTextures + 1 };
#endif // _Graphic3d_FrameStatsCounter_HeaderFile

View File

@ -0,0 +1,126 @@
// Copyright (c) 2018 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Graphic3d_FrameStatsData.hxx>
// =======================================================================
// function : Graphic3d_FrameStatsData
// purpose :
// =======================================================================
Graphic3d_FrameStatsData::Graphic3d_FrameStatsData()
: myFps (-1.0),
myFpsCpu (-1.0)
{
myCounters .resize (Graphic3d_FrameStatsCounter_NB, 0);
myTimers .resize (Graphic3d_FrameStatsTimer_NB, 0.0);
myTimersMin.resize (Graphic3d_FrameStatsTimer_NB, RealLast());
myTimersMax.resize (Graphic3d_FrameStatsTimer_NB, 0.0);
Reset();
}
// =======================================================================
// function : operator=
// purpose :
// =======================================================================
Graphic3d_FrameStatsData& Graphic3d_FrameStatsData::operator= (const Graphic3d_FrameStatsData& theOther)
{
myFps = theOther.myFps;
myFpsCpu = theOther.myFpsCpu;
myCounters = theOther.myCounters;
myTimers = theOther.myTimers;
myTimersMin = theOther.myTimersMin;
myTimersMax = theOther.myTimersMax;
return *this;
}
// =======================================================================
// function : Reset
// purpose :
// =======================================================================
void Graphic3d_FrameStatsData::Reset()
{
myFps = -1.0;
myFpsCpu = -1.0;
myCounters .assign (myCounters.size(), 0);
myTimers .assign (myTimers.size(), 0.0);
myTimersMin.assign (myTimersMin.size(), RealLast());
myTimersMax.assign (myTimersMax.size(), 0.0);
}
// =======================================================================
// function : FillMax
// purpose :
// =======================================================================
void Graphic3d_FrameStatsData::FillMax (const Graphic3d_FrameStatsData& theOther)
{
myFps = Max (myFps, theOther.myFps);
myFpsCpu = Max (myFpsCpu, theOther.myFpsCpu);
for (size_t aCounterIter = 0; aCounterIter < myCounters.size(); ++aCounterIter)
{
myCounters[aCounterIter] = myCounters[aCounterIter] > theOther.myCounters[aCounterIter] ? myCounters[aCounterIter] : theOther.myCounters[aCounterIter];
}
for (size_t aTimerIter = 0; aTimerIter < myTimers.size(); ++aTimerIter)
{
myTimersMax[aTimerIter] = Max (myTimersMax[aTimerIter], theOther.myTimersMax[aTimerIter]);
myTimersMin[aTimerIter] = Min (myTimersMin[aTimerIter], theOther.myTimersMin[aTimerIter]);
myTimers [aTimerIter] = myTimersMax[aTimerIter];
}
}
// =======================================================================
// function : Graphic3d_FrameStatsDataTmp
// purpose :
// =======================================================================
Graphic3d_FrameStatsDataTmp::Graphic3d_FrameStatsDataTmp()
{
myOsdTimers .resize (Graphic3d_FrameStatsTimer_NB, OSD_Timer (true));
myTimersPrev.resize (Graphic3d_FrameStatsTimer_NB, 0.0);
}
// =======================================================================
// function : FlushTimers
// purpose :
// =======================================================================
void Graphic3d_FrameStatsDataTmp::FlushTimers (Standard_Size theNbFrames, bool theIsFinal)
{
for (size_t aTimerIter = 0; aTimerIter < myTimers.size(); ++aTimerIter)
{
const Standard_Real aFrameTime = myTimers[aTimerIter] - myTimersPrev[aTimerIter];
myTimersMax [aTimerIter] = Max (myTimersMax[aTimerIter], aFrameTime);
myTimersMin [aTimerIter] = Min (myTimersMin[aTimerIter], aFrameTime);
myTimersPrev[aTimerIter] = myTimers[aTimerIter];
}
if (theIsFinal)
{
const Standard_Real aNbFrames = (Standard_Real )theNbFrames;
for (size_t aTimerIter = 0; aTimerIter < myTimers.size(); ++aTimerIter)
{
myTimers[aTimerIter] /= aNbFrames;
}
}
}
// =======================================================================
// function : Reset
// purpose :
// =======================================================================
void Graphic3d_FrameStatsDataTmp::Reset()
{
Graphic3d_FrameStatsData::Reset();
myTimersPrev.assign (myTimersPrev.size(), 0.0);
for (size_t aTimerIter = 0; aTimerIter < myOsdTimers.size(); ++aTimerIter)
{
myOsdTimers[aTimerIter].Reset();
}
}

View File

@ -0,0 +1,118 @@
// Copyright (c) 2018 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _Graphic3d_FrameStatsData_HeaderFile
#define _Graphic3d_FrameStatsData_HeaderFile
#include <NCollection_Array1.hxx>
#include <Graphic3d_FrameStatsCounter.hxx>
#include <Graphic3d_FrameStatsTimer.hxx>
#include <OSD_Timer.hxx>
#include <vector>
//! Data frame definition.
class Graphic3d_FrameStatsData
{
public:
DEFINE_STANDARD_ALLOC
//! Returns FPS (frames per seconds, elapsed time).
//! This number indicates an actual frame rate averaged for several frames within UpdateInterval() duration,
//! basing on a real elapsed time between updates.
Standard_Real FrameRate() const { return myFps; }
//! Returns CPU FPS (frames per seconds, CPU time).
//! This number indicates a PREDICTED frame rate,
//! basing on CPU elapsed time between updates and NOT real elapsed time (which might include periods of CPU inactivity).
//! Number is expected to be greater then actual frame rate returned by FrameRate().
//! Values significantly greater actual frame rate indicate that rendering is limited by GPU performance (CPU is stalled in-between),
//! while values around actual frame rate indicate rendering being limited by CPU performance (GPU is stalled in-between).
Standard_Real FrameRateCpu() const { return myFpsCpu; }
//! Get counter value.
Standard_Size CounterValue (Graphic3d_FrameStatsCounter theIndex) const { return myCounters[theIndex]; }
//! Get counter value.
Standard_Size operator[] (Graphic3d_FrameStatsCounter theIndex) const { return CounterValue (theIndex); }
//! Get timer value.
Standard_Real TimerValue (Graphic3d_FrameStatsTimer theIndex) const { return myTimers[theIndex]; }
//! Get timer value.
Standard_Real operator[] (Graphic3d_FrameStatsTimer theIndex) const { return TimerValue (theIndex); }
//! Empty constructor.
Standard_EXPORT Graphic3d_FrameStatsData();
//! Assignment operator.
Standard_EXPORT Graphic3d_FrameStatsData& operator= (const Graphic3d_FrameStatsData& theOther);
//! Reset data.
Standard_EXPORT void Reset();
//! Fill with maximum values.
Standard_EXPORT void FillMax (const Graphic3d_FrameStatsData& theOther);
protected:
std::vector<Standard_Size> myCounters; //!< counters
std::vector<Standard_Real> myTimers; //!< timers
std::vector<Standard_Real> myTimersMin; //!< minimal values of timers
std::vector<Standard_Real> myTimersMax; //!< maximum values of timers
Standard_Real myFps; //!< FPS meter (frames per seconds, elapsed time)
Standard_Real myFpsCpu; //!< CPU FPS meter (frames per seconds, CPU time)
};
//! Temporary data frame definition.
class Graphic3d_FrameStatsDataTmp : public Graphic3d_FrameStatsData
{
public:
//! Empty constructor.
Standard_EXPORT Graphic3d_FrameStatsDataTmp();
//! Compute average data considering the amount of rendered frames.
Standard_EXPORT void FlushTimers (Standard_Size theNbFrames, bool theIsFinal);
//! Reset data.
Standard_EXPORT void Reset();
//! Assignment operator (skip copying irrelevant properties).
void operator= (const Graphic3d_FrameStatsData& theOther) { Graphic3d_FrameStatsData::operator= (theOther); }
//! Returns FPS (frames per seconds, elapsed time).
Standard_Real& ChangeFrameRate() { return myFps; }
//! Returns CPU FPS (frames per seconds, CPU time).
Standard_Real& ChangeFrameRateCpu() { return myFpsCpu; }
//! Return a timer object for time measurements.
OSD_Timer& ChangeTimer (Graphic3d_FrameStatsTimer theTimer) { return myOsdTimers[theTimer]; }
//! Get counter value.
Standard_Size& ChangeCounterValue (Graphic3d_FrameStatsCounter theIndex) { return myCounters[theIndex]; }
//! Modify counter value.
Standard_Size& operator[] (Graphic3d_FrameStatsCounter theIndex) { return ChangeCounterValue (theIndex); }
//! Modify timer value.
Standard_Real& ChangeTimerValue (Graphic3d_FrameStatsTimer theIndex) { return myTimers[theIndex]; }
//! Modify timer value.
Standard_Real& operator[] (Graphic3d_FrameStatsTimer theIndex) { return ChangeTimerValue (theIndex); }
protected:
std::vector<OSD_Timer> myOsdTimers; //!< precise timers for time measurements
std::vector<Standard_Real> myTimersPrev; //!< previous timers values
};
#endif // _Graphic3d_FrameStatsData_HeaderFile

View File

@ -0,0 +1,28 @@
// Copyright (c) 2018 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _Graphic3d_FrameStatsTimer_HeaderFile
#define _Graphic3d_FrameStatsTimer_HeaderFile
//! Timers for collecting frame performance statistics.
enum Graphic3d_FrameStatsTimer
{
Graphic3d_FrameStatsTimer_ElapsedFrame,
Graphic3d_FrameStatsTimer_CpuFrame,
Graphic3d_FrameStatsTimer_CpuCulling,
Graphic3d_FrameStatsTimer_CpuPicking,
Graphic3d_FrameStatsTimer_CpuDynamics,
};
enum { Graphic3d_FrameStatsTimer_NB = Graphic3d_FrameStatsTimer_CpuDynamics + 1 };
#endif // _Graphic3d_FrameStatsTimer_HeaderFile

View File

@ -46,11 +46,12 @@ public:
};
//! Statistics display flags.
//! If not specified otherwise, the counter value is computed for a single rendered frame.
enum PerfCounters
{
PerfCounters_NONE = 0x000, //!< no stats
PerfCounters_FrameRate = 0x001, //!< Frame Rate
PerfCounters_CPU = 0x002, //!< CPU utilization
PerfCounters_FrameRate = 0x001, //!< Frame Rate, frames per second (number of frames within elapsed time)
PerfCounters_CPU = 0x002, //!< CPU utilization as frames per second (number of frames within CPU utilization time (rendering thread))
PerfCounters_Layers = 0x004, //!< count layers (groups of structures)
PerfCounters_Structures = 0x008, //!< count low-level Structures (normal unhighlighted Presentable Object is usually represented by 1 Structure)
//
@ -61,6 +62,11 @@ public:
PerfCounters_Points = 0x080, //!< count Points
//
PerfCounters_EstimMem = 0x100, //!< estimated GPU memory usage
//
PerfCounters_FrameTime = 0x200, //!< frame CPU utilization time (rendering thread); @sa Graphic3d_FrameStatsTimer
PerfCounters_FrameTimeMax= 0x400, //!< maximum frame times
//
PerfCounters_SkipImmediate = 0x800, //!< do not include immediate viewer updates (e.g. lazy updates without redrawing entire view content)
//! show basic statistics
PerfCounters_Basic = PerfCounters_FrameRate | PerfCounters_CPU | PerfCounters_Layers | PerfCounters_Structures,
//! extended (verbose) statistics
@ -68,6 +74,10 @@ public:
| PerfCounters_Groups | PerfCounters_GroupArrays
| PerfCounters_Triangles | PerfCounters_Points
| PerfCounters_EstimMem,
//! all counters
PerfCounters_All = PerfCounters_Extended
| PerfCounters_FrameTime
| PerfCounters_FrameTimeMax,
};
public:
@ -106,10 +116,14 @@ public:
AnaglyphFilter (Anaglyph_RedCyan_Optimized),
ToReverseStereo (Standard_False),
//
StatsPosition (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i (20, 20))),
StatsPosition (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i (20, 20))),
ChartPosition (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_RIGHT_UPPER, Graphic3d_Vec2i (20, 20))),
ChartSize (-1, -1),
StatsTextAspect (new Graphic3d_AspectText3d()),
StatsUpdateInterval (1.0),
StatsTextHeight (16),
StatsNbFrames (1),
StatsMaxChartTime (0.1f),
CollectedStats (PerfCounters_Basic),
ToShowStats (Standard_False),
//
@ -179,12 +193,16 @@ public:
Standard_Boolean ToReverseStereo; //!< flag to reverse stereo pair, FALSE by default
Handle(Graphic3d_TransformPers) StatsPosition; //!< location of stats, upper-left position by default
Handle(Graphic3d_TransformPers) ChartPosition; //!< location of stats chart, upper-right position by default
Graphic3d_Vec2i ChartSize; //!< chart size in pixels, (-1, -1) by default which means that chart will occupy a portion of viewport
Handle(Graphic3d_AspectText3d) StatsTextAspect; //!< stats text aspect
Standard_ShortReal StatsUpdateInterval; //!< time interval between stats updates in seconds, 1.0 second by default;
//! too often updates might impact performance and will smear text within widgets
//! (especially framerate, which is better averaging);
//! 0.0 interval will force updating on each frame
Standard_Integer StatsTextHeight; //!< stats text size; 16 by default
Standard_Integer StatsNbFrames; //!< number of data frames to collect history; 1 by default
Standard_ShortReal StatsMaxChartTime; //!< upper time limit within frame chart in seconds; 0.1 seconds by default (100 ms or 10 FPS)
PerfCounters CollectedStats; //!< performance counters to collect, PerfCounters_Basic by default;
//! too verbose options might impact rendering performance,
//! because some counters might lack caching optimization (and will require expensive iteration through all data structures)

View File

@ -611,6 +611,10 @@ public: //! @name methods to alter or retrieve current state
//! Return structure holding frame statistics.
const Handle(OpenGl_FrameStats)& FrameStats() const { return myFrameStats; }
//! Set structure holding frame statistics.
//! This call makes sense only if application defines OpenGl_FrameStats sub-class.
void SetFrameStats (const Handle(OpenGl_FrameStats)& theStats) { myFrameStats = theStats; }
//! Return cached viewport definition (x, y, width, height).
const Standard_Integer* Viewport() const { return myViewport; }

View File

@ -17,86 +17,10 @@
#include <OpenGl_View.hxx>
#include <OpenGl_Workspace.hxx>
IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameStats, Standard_Transient)
IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameStats, Graphic3d_FrameStats)
namespace
{
//! Format counter.
static std::ostream& formatCounter (std::ostream& theStream,
Standard_Integer theWidth,
const char* thePrefix,
Standard_Size theValue,
const char* thePostfix = NULL)
{
if (thePrefix != NULL)
{
theStream << thePrefix;
}
theStream << std::setfill(' ') << std::setw (theWidth);
if (theValue >= 1000000000)
{
Standard_Real aValM = Standard_Real(theValue) / 1000000000.0;
theStream << std::fixed << std::setprecision (1) << aValM << "G";
}
else if (theValue >= 1000000)
{
Standard_Real aValM = Standard_Real(theValue) / 1000000.0;
theStream << std::fixed << std::setprecision (1) << aValM << "M";
}
else if (theValue >= 1000)
{
Standard_Real aValK = Standard_Real(theValue) / 1000.0;
theStream << std::fixed << std::setprecision (1) << aValK << "k";
}
else
{
theStream << theValue;
}
if (thePostfix != NULL)
{
theStream << thePostfix;
}
return theStream;
}
//! Format memory counter.
static std::ostream& formatBytes (std::ostream& theStream,
Standard_Integer theWidth,
const char* thePrefix,
Standard_Size theValue,
const char* thePostfix = NULL)
{
if (thePrefix != NULL)
{
theStream << thePrefix;
}
theStream << std::setfill(' ') << std::setw (theWidth);
if (theValue >= 1024 * 1024 * 1024)
{
Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0 * 1024.0);
theStream << std::fixed << std::setprecision (1) << aValM << " GiB";
}
else if (theValue >= 1024 * 1024)
{
Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0);
theStream << std::fixed << std::setprecision (1) << aValM << " MiB";
}
else if (theValue >= 1024)
{
Standard_Real aValK = Standard_Real(theValue) / 1024.0;
theStream << std::fixed << std::setprecision (1) << aValK << " KiB";
}
else
{
theStream << theValue;
}
if (thePostfix != NULL)
{
theStream << thePostfix;
}
return theStream;
}
//! Return estimated data size.
static Standard_Size estimatedDataSize (const Handle(OpenGl_Resource)& theRes)
{
@ -109,17 +33,8 @@ namespace
// purpose :
// =======================================================================
OpenGl_FrameStats::OpenGl_FrameStats()
: myFpsTimer (Standard_True),
myFrameStartTime (0.0),
myFrameDuration (0.0),
myFps (-1.0),
myFpsCpu (-1.0),
myUpdateInterval (1.0),
myFpsFrameCount (0),
myIsLongLineFormat (Standard_False)
{
memset (myCounters, 0, sizeof(myCounters));
memset (myCountersTmp, 0, sizeof(myCountersTmp));
//
}
// =======================================================================
@ -132,173 +47,49 @@ OpenGl_FrameStats::~OpenGl_FrameStats()
}
// =======================================================================
// function : FormatStats
// function : IsFrameUpdated
// purpose :
// =======================================================================
TCollection_AsciiString OpenGl_FrameStats::FormatStats (Graphic3d_RenderingParams::PerfCounters theFlags) const
bool OpenGl_FrameStats::IsFrameUpdated (Handle(OpenGl_FrameStats)& thePrev) const
{
const Standard_Integer aValWidth = 5;
std::stringstream aBuf;
const Standard_Boolean isCompact = theFlags == Graphic3d_RenderingParams::PerfCounters_FrameRate; // only FPS is displayed
if (myIsLongLineFormat
&& (theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0
&& (theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
const Graphic3d_FrameStatsData& aFrame = LastDataFrame();
if (thePrev.IsNull())
{
aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 9) << std::fixed << std::setprecision (1) << myFps
<< " [CPU: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 10) << std::fixed << std::setprecision (1) << myFpsCpu << "]\n";
thePrev = new OpenGl_FrameStats();
}
else
// check just a couple of major counters
else if (myLastFrameIndex == thePrev->myLastFrameIndex
&& Abs (aFrame.FrameRate() - thePrev->myCountersTmp.FrameRate()) <= 0.001
&& Abs (aFrame.FrameRateCpu() - thePrev->myCountersTmp.FrameRateCpu()) <= 0.001
&& aFrame[Graphic3d_FrameStatsCounter_NbLayers] == thePrev->myCountersTmp[Graphic3d_FrameStatsCounter_NbLayers]
&& aFrame[Graphic3d_FrameStatsCounter_NbLayersNotCulled] == thePrev->myCountersTmp[Graphic3d_FrameStatsCounter_NbLayersNotCulled]
&& aFrame[Graphic3d_FrameStatsCounter_NbStructs] == thePrev->myCountersTmp[Graphic3d_FrameStatsCounter_NbStructs]
&& aFrame[Graphic3d_FrameStatsCounter_NbStructsNotCulled] == thePrev->myCountersTmp[Graphic3d_FrameStatsCounter_NbStructsNotCulled])
{
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
{
aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << myFps << "\n";
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
{
aBuf << "CPU FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << myFpsCpu << "\n";
}
return false;
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
{
if (myIsLongLineFormat)
{
formatCounter (aBuf, aValWidth, "Layers: ", myCounters[Counter_NbLayers]);
if (HasCulledLayers())
{
formatCounter (aBuf, aValWidth, " [rendered: ", myCounters[Counter_NbLayersNotCulled], "]");
}
aBuf << "\n";
}
else
{
formatCounter (aBuf, aValWidth + 3, "Layers: ", myCounters[Counter_NbLayers], "\n");
}
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
{
if (myIsLongLineFormat)
{
formatCounter (aBuf, aValWidth, "Structs: ", myCounters[Counter_NbStructs]);
if (HasCulledStructs())
{
formatCounter (aBuf, aValWidth, " [rendered: ", myCounters[Counter_NbStructsNotCulled], "]");
}
aBuf << "\n";
}
else
{
formatCounter (aBuf, aValWidth + 3, "Structs: ", myCounters[Counter_NbStructs], "\n");
}
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0
|| (!myIsLongLineFormat
&& ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)))
{
aBuf << "Rendered\n";
}
if (!myIsLongLineFormat
&& (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
{
formatCounter (aBuf, aValWidth, " Layers: ", myCounters[Counter_NbLayersNotCulled], "\n");
}
if (!myIsLongLineFormat
&& (theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
{
formatCounter (aBuf, aValWidth, " Structs: ", myCounters[Counter_NbStructsNotCulled], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
{
formatCounter (aBuf, aValWidth, " Groups: ", myCounters[Counter_NbGroupsNotCulled], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
{
formatCounter (aBuf, aValWidth, " Arrays: ", myCounters[Counter_NbElemsNotCulled], "\n");
formatCounter (aBuf, aValWidth, " [fill]: ", myCounters[Counter_NbElemsFillNotCulled], "\n");
formatCounter (aBuf, aValWidth, " [line]: ", myCounters[Counter_NbElemsLineNotCulled], "\n");
formatCounter (aBuf, aValWidth, " [point]: ", myCounters[Counter_NbElemsPointNotCulled], "\n");
formatCounter (aBuf, aValWidth, " [text]: ", myCounters[Counter_NbElemsTextNotCulled], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
{
formatCounter (aBuf, aValWidth, " Triangles: ", myCounters[Counter_NbTrianglesNotCulled], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
{
formatCounter (aBuf, aValWidth, " Points: ", myCounters[Counter_NbPointsNotCulled], "\n");
}
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
{
aBuf << "GPU Memory\n";
formatBytes (aBuf, aValWidth, " Geometry: ", myCounters[Counter_EstimatedBytesGeom], "\n");
formatBytes (aBuf, aValWidth, " Textures: ", myCounters[Counter_EstimatedBytesTextures], "\n");
formatBytes (aBuf, aValWidth, " Frames: ", myCounters[Counter_EstimatedBytesFbos], "\n");
}
return TCollection_AsciiString (aBuf.str().c_str());
thePrev->myLastFrameIndex = myLastFrameIndex;
thePrev->myCountersTmp = aFrame;
return true;
}
// =======================================================================
// function : FrameStart
// function : updateStatistics
// purpose :
// =======================================================================
void OpenGl_FrameStats::FrameStart (const Handle(OpenGl_Workspace)& )
void OpenGl_FrameStats::updateStatistics (const Handle(Graphic3d_CView)& theView,
bool theIsImmediateOnly)
{
memset (myCountersTmp, 0, sizeof(myCountersTmp));
myFrameStartTime = myFpsTimer.ElapsedTime();
if (!myFpsTimer.IsStarted())
{
myFpsTimer.Reset();
myFpsTimer.Start();
myFpsFrameCount = 0;
}
}
// =======================================================================
// function : FrameEnd
// purpose :
// =======================================================================
void OpenGl_FrameStats::FrameEnd (const Handle(OpenGl_Workspace)& theWorkspace)
{
const Graphic3d_RenderingParams::PerfCounters aBits = !theWorkspace.IsNull()
? theWorkspace->View()->RenderingParams().CollectedStats
: Graphic3d_RenderingParams::PerfCounters_NONE;
const double aTime = myFpsTimer.ElapsedTime();
myFrameDuration = aTime - myFrameStartTime;
++myFpsFrameCount;
if (!theWorkspace.IsNull())
{
myUpdateInterval = theWorkspace->View()->RenderingParams().StatsUpdateInterval;
}
if (aTime < myUpdateInterval)
const OpenGl_View* aView = dynamic_cast<const OpenGl_View*> (theView.get());
if (aView == NULL)
{
myCounters.SetValue (myLastFrameIndex, myCountersTmp);
myCountersTmp.Reset();
return;
}
if (aTime > gp::Resolution())
{
// update FPS
myFpsTimer.Stop();
const double aCpuSec = myFpsTimer.UserTimeCPU();
myFps = double(myFpsFrameCount) / aTime;
myFpsCpu = aCpuSec > gp::Resolution()
? double(myFpsFrameCount) / aCpuSec
: -1.0;
myFpsTimer.Reset();
myFpsTimer.Start();
myFpsFrameCount = 0;
}
// update structure counters
if (theWorkspace.IsNull())
{
memcpy (myCounters, myCountersTmp, sizeof(myCounters));
return;
}
const Graphic3d_RenderingParams::PerfCounters aBits = theView->RenderingParams().CollectedStats;
const Standard_Boolean toCountMem = (aBits & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0;
const Standard_Boolean toCountTris = (aBits & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
|| (aBits & Graphic3d_RenderingParams::PerfCounters_Points) != 0;
@ -307,20 +98,25 @@ void OpenGl_FrameStats::FrameEnd (const Handle(OpenGl_Workspace)& theWorkspace)
const Standard_Boolean toCountStructs = (aBits & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
|| (aBits & Graphic3d_RenderingParams::PerfCounters_Layers) != 0 || toCountGroups;
myCountersTmp[Counter_NbLayers] = theWorkspace->View()->LayerList().Layers().Size();
myCountersTmp[Graphic3d_FrameStatsCounter_NbLayers] = aView->LayerList().Layers().Size();
if (toCountStructs
|| (aBits & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
{
const Standard_Integer aViewId = theWorkspace->View()->Identification();
for (OpenGl_SequenceOfLayers::Iterator aLayerIter (theWorkspace->View()->LayerList().Layers()); aLayerIter.More(); aLayerIter.Next())
const Standard_Integer aViewId = aView->Identification();
for (OpenGl_SequenceOfLayers::Iterator aLayerIter (aView->LayerList().Layers()); aLayerIter.More(); aLayerIter.Next())
{
const Handle(OpenGl_Layer)& aLayer = aLayerIter.Value();
myCountersTmp[Graphic3d_FrameStatsCounter_NbStructs] += aLayer->NbStructures();
if (theIsImmediateOnly && !aLayer->LayerSettings().IsImmediate())
{
continue;
}
if (!aLayer->IsCulled())
{
++myCountersTmp[Counter_NbLayersNotCulled];
++myCountersTmp[Graphic3d_FrameStatsCounter_NbLayersNotCulled];
}
myCountersTmp[Counter_NbStructs] += aLayer->NbStructures();
myCountersTmp[Counter_NbStructsNotCulled] += aLayer->NbStructuresNotCulled();
myCountersTmp[Graphic3d_FrameStatsCounter_NbStructsNotCulled] += aLayer->NbStructuresNotCulled();
if (toCountGroups)
{
updateStructures (aViewId, aLayer->CullableStructuresBVH().Structures(), toCountElems, toCountTris, toCountMem);
@ -329,18 +125,16 @@ void OpenGl_FrameStats::FrameEnd (const Handle(OpenGl_Workspace)& theWorkspace)
}
}
}
if (toCountMem
&& !theWorkspace.IsNull())
if (toCountMem)
{
for (OpenGl_Context::OpenGl_ResourcesMap::Iterator aResIter (theWorkspace->GetGlContext()->SharedResources());
for (OpenGl_Context::OpenGl_ResourcesMap::Iterator aResIter (aView->GlWindow()->GetGlContext()->SharedResources());
aResIter.More(); aResIter.Next())
{
myCountersTmp[Counter_EstimatedBytesTextures] += aResIter.Value()->EstimatedDataSize();
myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesTextures] += aResIter.Value()->EstimatedDataSize();
}
const OpenGl_View* aView = theWorkspace->View();
{
Standard_Size& aMemFbos = myCountersTmp[Counter_EstimatedBytesFbos];
Standard_Size& aMemFbos = myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesFbos];
// main FBOs
aMemFbos += estimatedDataSize (aView->myMainSceneFbos[0]);
aMemFbos += estimatedDataSize (aView->myMainSceneFbos[1]);
@ -370,7 +164,7 @@ void OpenGl_FrameStats::FrameEnd (const Handle(OpenGl_Workspace)& theWorkspace)
}
{
// Ray Tracing geometry
Standard_Size& aMemGeom = myCountersTmp[Counter_EstimatedBytesGeom];
Standard_Size& aMemGeom = myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesGeom];
aMemGeom += estimatedDataSize (aView->mySceneNodeInfoTexture);
aMemGeom += estimatedDataSize (aView->mySceneMinPointTexture);
aMemGeom += estimatedDataSize (aView->mySceneMaxPointTexture);
@ -383,7 +177,6 @@ void OpenGl_FrameStats::FrameEnd (const Handle(OpenGl_Workspace)& theWorkspace)
aMemGeom += estimatedDataSize (aView->myRaytraceLightSrcTexture);
}
}
memcpy (myCounters, myCountersTmp, sizeof(myCounters));
}
// =======================================================================
@ -414,8 +207,8 @@ void OpenGl_FrameStats::updateStructures (Standard_Integer theViewId,
{
if (const OpenGl_PrimitiveArray* aPrim = dynamic_cast<const OpenGl_PrimitiveArray*> (aNodeIter->elem))
{
myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
}
}
}
@ -423,7 +216,7 @@ void OpenGl_FrameStats::updateStructures (Standard_Integer theViewId,
continue;
}
myCountersTmp[Counter_NbGroupsNotCulled] += aStruct->Groups().Size();
myCountersTmp[Graphic3d_FrameStatsCounter_NbGroupsNotCulled] += aStruct->Groups().Size();
if (!theToCountElems)
{
continue;
@ -436,16 +229,16 @@ void OpenGl_FrameStats::updateStructures (Standard_Integer theViewId,
{
if (const OpenGl_PrimitiveArray* aPrim = dynamic_cast<const OpenGl_PrimitiveArray*> (aNodeIter->elem))
{
++myCountersTmp[Counter_NbElemsNotCulled];
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsNotCulled];
if (theToCountMem)
{
myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
}
if (aPrim->IsFillDrawMode())
{
++myCountersTmp[Counter_NbElemsFillNotCulled];
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled];
if (!theToCountTris)
{
continue;
@ -465,34 +258,34 @@ void OpenGl_FrameStats::updateStructures (Standard_Integer theViewId,
{
case GL_TRIANGLES:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 3;
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices / 3;
break;
}
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices - 2 * aNbBounds;
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices - 2 * aNbBounds;
break;
}
case GL_TRIANGLES_ADJACENCY:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 6;
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices / 6;
break;
}
case GL_TRIANGLE_STRIP_ADJACENCY:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices - 4 * aNbBounds;
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices - 4 * aNbBounds;
break;
}
#if !defined(GL_ES_VERSION_2_0)
case GL_QUADS:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 2;
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices / 2;
break;
}
case GL_QUAD_STRIP:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += (aNbIndices / 2 - aNbBounds) * 2;
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += (aNbIndices / 2 - aNbBounds) * 2;
break;
}
#endif
@ -500,7 +293,7 @@ void OpenGl_FrameStats::updateStructures (Standard_Integer theViewId,
}
else if (aPrim->DrawMode() == GL_POINTS)
{
++myCountersTmp[Counter_NbElemsPointNotCulled];
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled];
if (theToCountTris)
{
const Handle(OpenGl_VertexBuffer)& anAttribs = aPrim->AttributesVbo();
@ -509,20 +302,20 @@ void OpenGl_FrameStats::updateStructures (Standard_Integer theViewId,
{
const Handle(OpenGl_VertexBuffer)& anIndices = aPrim->IndexVbo();
const Standard_Integer aNbIndices = !anIndices.IsNull() ? anIndices->GetElemsNb() : anAttribs->GetElemsNb();
myCountersTmp[Counter_NbPointsNotCulled] += aNbIndices;
myCountersTmp[Graphic3d_FrameStatsCounter_NbPointsNotCulled] += aNbIndices;
}
}
}
else
{
++myCountersTmp[Counter_NbElemsLineNotCulled];
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled];
}
}
else if (const OpenGl_Text* aText = dynamic_cast<const OpenGl_Text*> (aNodeIter->elem))
{
(void )aText;
++myCountersTmp[Counter_NbElemsNotCulled];
++myCountersTmp[Counter_NbElemsTextNotCulled];
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsNotCulled];
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled];
}
}
}

View File

@ -14,43 +14,17 @@
#ifndef _OpenGl_FrameStats_HeaderFile
#define _OpenGl_FrameStats_HeaderFile
#include <Graphic3d_RenderingParams.hxx>
#include <Graphic3d_FrameStats.hxx>
#include <NCollection_IndexedMap.hxx>
#include <OSD_Timer.hxx>
#include <Standard_Type.hxx>
#include <Standard_Transient.hxx>
class OpenGl_Workspace;
class OpenGl_Structure;
typedef NCollection_IndexedMap<const OpenGl_Structure*> OpenGl_IndexedMapOfStructure;
//! Class storing the frame statistics.
class OpenGl_FrameStats : public Standard_Transient
class OpenGl_FrameStats : public Graphic3d_FrameStats
{
DEFINE_STANDARD_RTTIEXT(OpenGl_FrameStats, Standard_Transient)
public:
//! Stats counter.
enum Counter
{
Counter_NbLayers = 0, //!< number of ZLayers
Counter_NbLayersNotCulled, //!< number of not culled ZLayers
Counter_NbStructs, //!< number of defined OpenGl_Structure
Counter_NbStructsNotCulled, //!< number of not culled OpenGl_Structure
Counter_NbGroupsNotCulled, //!< number of not culled OpenGl_Group
Counter_NbElemsNotCulled, //!< number of not culled OpenGl_Element
Counter_NbElemsFillNotCulled, //!< number of not culled OpenGl_PrimitiveArray drawing triangles
Counter_NbElemsLineNotCulled, //!< number of not culled OpenGl_PrimitiveArray drawing lines
Counter_NbElemsPointNotCulled, //!< number of not culled OpenGl_PrimitiveArray drawing points
Counter_NbElemsTextNotCulled, //!< number of not culled OpenGl_Text
Counter_NbTrianglesNotCulled, //!< number of not culled (as structure) triangles
Counter_NbPointsNotCulled, //!< number of not culled (as structure) points
Counter_EstimatedBytesGeom, //!< estimated GPU memory used for geometry
Counter_EstimatedBytesFbos, //!< estimated GPU memory used for FBOs
Counter_EstimatedBytesTextures, //!< estimated GPU memory used for textures
};
enum { Counter_NB = Counter_EstimatedBytesTextures + 1 };
DEFINE_STANDARD_RTTIEXT(OpenGl_FrameStats, Graphic3d_FrameStats)
public:
//! Default constructor.
@ -59,82 +33,19 @@ public:
//! Destructor.
Standard_EXPORT virtual ~OpenGl_FrameStats();
//! Returns interval in seconds for updating meters across several frames; 1 second by default.
Standard_Real UpdateInterval() const { return myUpdateInterval; }
//! Sets interval in seconds for updating values.
void SetUpdateInterval (Standard_Real theInterval) { myUpdateInterval = theInterval; }
//! Prefer longer lines over more greater of lines.
Standard_Boolean IsLongLineFormat() const { return myIsLongLineFormat; }
//! Set if format should prefer longer lines over greater number of lines.
void SetLongLineFormat (Standard_Boolean theValue) { myIsLongLineFormat = theValue; }
//! Frame redraw started.
Standard_EXPORT virtual void FrameStart (const Handle(OpenGl_Workspace)& theWorkspace = Handle(OpenGl_Workspace)());
//! Frame redraw finished.
Standard_EXPORT virtual void FrameEnd (const Handle(OpenGl_Workspace)& theWorkspace = Handle(OpenGl_Workspace)());
public:
//! Returns formatted string.
Standard_EXPORT virtual TCollection_AsciiString FormatStats (Graphic3d_RenderingParams::PerfCounters theFlags) const;
//! Returns duration of the last frame in seconds.
Standard_Real FrameDuration() const { return myFrameDuration; }
//! Returns FPS (frames per seconds, elapsed time).
//! This number indicates an actual frame rate averaged for several frames within UpdateInterval() duration,
//! basing on a real elapsed time between updates.
Standard_Real FrameRate() const { return myFps; }
//! Returns CPU FPS (frames per seconds, CPU time).
//! This number indicates a PREDICTED frame rate,
//! basing on CPU elapsed time between updates and NOT real elapsed time (which might include periods of CPU inactivity).
//! Number is expected to be greater then actual frame rate returned by FrameRate().
//! Values significantly greater actual frame rate indicate that rendering is limited by GPU performance (CPU is stalled in-between),
//! while values around actual frame rate indicate rendering being limited by CPU performance (GPU is stalled in-between).
Standard_Real FrameRateCpu() const { return myFpsCpu; }
//! Returns value of specified counter, cached between stats updates.
//! Should NOT be called between ::FrameStart() and ::FrameEnd() calls.
Standard_Size CounterValue (OpenGl_FrameStats::Counter theCounter) const { return myCounters[theCounter]; }
//! Returns TRUE if some Layers have been culled.
Standard_Boolean HasCulledLayers() const { return myCounters[Counter_NbLayersNotCulled] != myCounters[Counter_NbLayers]; }
//! Returns TRUE if some structures have been culled.
Standard_Boolean HasCulledStructs() const { return myCounters[Counter_NbStructsNotCulled] != myCounters[Counter_NbStructs]; }
public:
//! Returns TRUE if this stats are equal to another.
virtual Standard_Boolean IsEqual (const Handle(OpenGl_FrameStats)& theOther) const
{
// check just a couple of major counters
return Abs (myFps - theOther->myFps) <= 0.001
&& Abs (myFpsCpu - theOther->myFpsCpu) <= 0.001
&& myCounters[Counter_NbLayers] == theOther->myCounters[Counter_NbLayers]
&& myCounters[Counter_NbLayersNotCulled] == theOther->myCounters[Counter_NbLayersNotCulled]
&& myCounters[Counter_NbStructs] == theOther->myCounters[Counter_NbStructs]
&& myCounters[Counter_NbStructsNotCulled] == theOther->myCounters[Counter_NbStructsNotCulled];
}
//! Copy stats values from another instance
virtual void CopyFrom (const Handle(OpenGl_FrameStats)& theOther)
{
myFps = theOther->myFps;
myFpsCpu = theOther->myFpsCpu;
memcpy (myCounters, theOther->myCounters, sizeof(myCounters));
}
//! Returns value of specified counter for modification, should be called between ::FrameStart() and ::FrameEnd() calls.
Standard_Size& ChangeCounter (OpenGl_FrameStats::Counter theCounter) { return myCountersTmp[theCounter]; }
//! Copy stats values into another instance (create new instance, if not exists).
//! The main use of this method is to track changes in statistics (e.g. in conjunction with IsEqual() method).
//! @return TRUE if frame data has been changed so that the presentation should be updated
Standard_EXPORT virtual bool IsFrameUpdated (Handle(OpenGl_FrameStats)& thePrev) const;
protected:
//! Method to collect statistics from the View; called by FrameEnd().
Standard_EXPORT virtual void updateStatistics (const Handle(Graphic3d_CView)& theView,
bool theIsImmediateOnly) Standard_OVERRIDE;
//! Updates counters for structures.
Standard_EXPORT virtual void updateStructures (Standard_Integer theViewId,
const OpenGl_IndexedMapOfStructure& theStructures,
@ -142,21 +53,8 @@ protected:
Standard_Boolean theToCountTris,
Standard_Boolean theToCountMem);
protected:
OSD_Timer myFpsTimer; //!< timer for FPS measurements
Standard_Real myFrameStartTime; //!< time at the beginning of frame redraw
Standard_Real myFrameDuration; //!< frame duration
Standard_Real myFps; //!< FPS meter (frames per seconds, elapsed time)
Standard_Real myFpsCpu; //!< CPU FPS meter (frames per seconds, CPU time)
Standard_Real myUpdateInterval; //!< interval to update meters
Standard_Size myFpsFrameCount; //!< FPS counter (within short measurement time slice)
Standard_Size myCounters [Counter_NB]; //!< counter values cached between updates
Standard_Size myCountersTmp[Counter_NB]; //!< counter values filled during
Standard_Boolean myIsLongLineFormat; //!< prefer longer lines over greater number of lines
};
DEFINE_STANDARD_HANDLE(OpenGl_FrameStats, Standard_Transient)
DEFINE_STANDARD_HANDLE(OpenGl_FrameStats, Graphic3d_FrameStats)
#endif // _OpenGl_FrameStats_HeaderFile

View File

@ -17,16 +17,40 @@
#include <OpenGl_ShaderManager.hxx>
#include <OpenGl_Workspace.hxx>
#include <Graphic3d_ArrayOfTriangles.hxx>
namespace
{
//! Auxiliary structure defining vertex with two attributes.
struct OpenGl_Vec3Vec4ub
{
Graphic3d_Vec3 Pos;
Graphic3d_Vec4ub Color;
};
//! Auxiliary function formatting rendering time in " 10 ms (100 FPS)" format.
static TCollection_AsciiString formatTimeMs (Standard_Real theSeconds)
{
const Standard_Real aFpsVal = theSeconds != 0.0 ? 1.0 / theSeconds : 0.0;
char aFps[50];
Sprintf (aFps, "%.1f", aFpsVal);
return TCollection_AsciiString() + Standard_Integer(theSeconds * 1000.0) + " ms (" + aFps + " FPS)";
}
}
// =======================================================================
// function : OpenGl_FrameStatsPrs
// purpose :
// =======================================================================
OpenGl_FrameStatsPrs::OpenGl_FrameStatsPrs()
: myStatsPrev (new OpenGl_FrameStats())
: myStatsPrev (new OpenGl_FrameStats()),
myCountersTrsfPers (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i (20, 20))),
myChartTrsfPers (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_RIGHT_UPPER, Graphic3d_Vec2i (20, 20))),
myChartVertices (new OpenGl_VertexBuffer()),
myChartIndices (new OpenGl_IndexBuffer()),
myChartLines (new OpenGl_VertexBuffer())
{
myParams.HAlign = Graphic3d_HTA_CENTER;
myParams.VAlign = Graphic3d_VTA_CENTER;
myHasPlane = false;
//
}
// =======================================================================
@ -44,7 +68,13 @@ OpenGl_FrameStatsPrs::~OpenGl_FrameStatsPrs()
// =======================================================================
void OpenGl_FrameStatsPrs::Release (OpenGl_Context* theCtx)
{
OpenGl_Text::Release (theCtx);
myCountersText.Release (theCtx);
myChartLabels[0].Release (theCtx);
myChartLabels[1].Release (theCtx);
myChartLabels[2].Release (theCtx);
myChartVertices->Release (theCtx);
myChartIndices->Release (theCtx);
myChartLines->Release (theCtx);
}
// =======================================================================
@ -56,48 +86,262 @@ void OpenGl_FrameStatsPrs::Update (const Handle(OpenGl_Workspace)& theWorkspace)
const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
const Handle(OpenGl_FrameStats)& aStats = aCtx->FrameStats();
const Graphic3d_RenderingParams& aRendParams = theWorkspace->View()->RenderingParams();
myTrsfPers = theWorkspace->View()->RenderingParams().StatsPosition;
myCountersTrsfPers = theWorkspace->View()->RenderingParams().StatsPosition;
myChartTrsfPers = theWorkspace->View()->RenderingParams().ChartPosition;
myTextAspect.SetAspect (aRendParams.StatsTextAspect);
// adjust text alignment depending on corner
const OpenGl_TextParam aParamsPrev = myParams;
myParams.Height = aRendParams.StatsTextHeight;
myParams.HAlign = Graphic3d_HTA_CENTER;
myParams.VAlign = Graphic3d_VTA_CENTER;
if (!myTrsfPers.IsNull() && (myTrsfPers->Corner2d() & Aspect_TOTP_LEFT) != 0)
OpenGl_TextParam aParams;
aParams.Height = aRendParams.StatsTextHeight;
aParams.HAlign = Graphic3d_HTA_CENTER;
aParams.VAlign = Graphic3d_VTA_CENTER;
if (!myCountersTrsfPers.IsNull() && (myCountersTrsfPers->Corner2d() & Aspect_TOTP_LEFT) != 0)
{
myParams.HAlign = Graphic3d_HTA_LEFT;
aParams.HAlign = Graphic3d_HTA_LEFT;
}
else if (!myTrsfPers.IsNull() && (myTrsfPers->Corner2d() & Aspect_TOTP_RIGHT) != 0)
else if (!myCountersTrsfPers.IsNull() && (myCountersTrsfPers->Corner2d() & Aspect_TOTP_RIGHT) != 0)
{
myParams.HAlign = Graphic3d_HTA_RIGHT;
aParams.HAlign = Graphic3d_HTA_RIGHT;
}
if (!myTrsfPers.IsNull() && (myTrsfPers->Corner2d() & Aspect_TOTP_TOP) != 0)
if (!myCountersTrsfPers.IsNull() && (myCountersTrsfPers->Corner2d() & Aspect_TOTP_TOP) != 0)
{
myParams.VAlign = Graphic3d_VTA_TOP;
aParams.VAlign = Graphic3d_VTA_TOP;
}
else if (!myTrsfPers.IsNull() && (myTrsfPers->Corner2d() & Aspect_TOTP_BOTTOM) != 0)
else if (!myCountersTrsfPers.IsNull() && (myCountersTrsfPers->Corner2d() & Aspect_TOTP_BOTTOM) != 0)
{
myParams.VAlign = Graphic3d_VTA_BOTTOM;
aParams.VAlign = Graphic3d_VTA_BOTTOM;
}
if (myParams.Height != aParamsPrev.Height
|| myParams.HAlign != aParamsPrev.HAlign
|| myParams.VAlign != aParamsPrev.VAlign)
if (aParams.Height != myCountersText.FormatParams().Height
|| aParams.HAlign != myCountersText.FormatParams().HAlign
|| aParams.VAlign != myCountersText.FormatParams().VAlign)
{
Release (aCtx.operator->());
myCountersText.Release (aCtx.operator->());
}
if (myStatsPrev->IsEqual (aStats)
&& !myString.IsEmpty())
if (!aStats->IsFrameUpdated (myStatsPrev)
&& !myCountersText.Text().IsEmpty())
{
return;
}
myStatsPrev->CopyFrom (aStats);
const TCollection_AsciiString aText = aStats->FormatStats (aRendParams.CollectedStats);
TCollection_AsciiString aText = aStats->FormatStats (aRendParams.CollectedStats);
myCountersText.Init (aCtx, aText.ToCString(), OpenGl_Vec3 (0.0f, 0.0f, 0.0f), aParams);
releaseVbos (aCtx.operator->());
myString.FromUnicode (aText.ToCString());
updateChart (theWorkspace);
}
// =======================================================================
// function : updateChart
// purpose :
// =======================================================================
void OpenGl_FrameStatsPrs::updateChart (const Handle(OpenGl_Workspace)& theWorkspace)
{
const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
const Handle(OpenGl_FrameStats)& aStats = aCtx->FrameStats();
const Graphic3d_RenderingParams& aRendParams = theWorkspace->View()->RenderingParams();
const Standard_Integer aNbBins = aStats->DataFrames().Size();
if (aNbBins <= 1)
{
return;
}
Standard_Real aMaxDuration = aRendParams.StatsMaxChartTime;
if (aMaxDuration <= 0.0f)
{
for (Standard_Integer aFrameIter = aStats->DataFrames().Lower(); aFrameIter <= aStats->DataFrames().Upper(); ++aFrameIter)
{
const Graphic3d_FrameStatsData& aFrame = aStats->DataFrames().Value (aFrameIter);
aMaxDuration = Max (aMaxDuration, aFrame.TimerValue (Graphic3d_FrameStatsTimer_ElapsedFrame));
}
aMaxDuration = Ceiling (aMaxDuration * 1000.0 * 0.1) * 0.001 * 10.0; // round number
aMaxDuration = Max (Min (aMaxDuration, 0.1), 0.005); // limit by 100 ms (10 FPS) and 5 ms (200 FPS)
}
const Standard_Integer aNbTimers = 4;
const Graphic3d_FrameStatsTimer aTimers[4] =
{
Graphic3d_FrameStatsTimer_CpuDynamics,
Graphic3d_FrameStatsTimer_CpuPicking,
Graphic3d_FrameStatsTimer_CpuCulling,
Graphic3d_FrameStatsTimer_ElapsedFrame,
};
const Graphic3d_Vec4ub aColors[4] =
{
Graphic3d_Vec4ub (255, 0, 0, 127),
Graphic3d_Vec4ub (255, 127, 39, 127),
Graphic3d_Vec4ub (255, 0, 0, 127),
Graphic3d_Vec4ub (0, 255, 0, 127),
};
const Standard_Integer aNbVerts = aNbBins * 4 * aNbTimers;
const Standard_Integer aNbIndexes = aNbBins * 2 * 3 * aNbTimers;
bool toFillEdges = false;
if (myChartArray.IsNull()
|| myChartArray->VertexNumber() != aNbVerts
|| myChartArray->EdgeNumber() != aNbIndexes)
{
myChartArray = new Graphic3d_ArrayOfTriangles (aNbVerts, aNbIndexes, false, true);
toFillEdges = true;
}
const Graphic3d_Vec2i aViewSize (aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);
Graphic3d_Vec2i aCharSize (aRendParams.ChartSize);
if (aCharSize.x() <= 0)
{
aCharSize.x() = aViewSize.x() / 2;
}
if (aCharSize.y() <= 0)
{
aCharSize.y() = Standard_Integer(0.15 * aViewSize.y());
}
const Graphic3d_Vec2d aBinSize (Standard_Real(aCharSize.x()) / Standard_Real(aNbBins), 0.15 * aViewSize.y());
Graphic3d_Vec2i anOffset;
if (!myChartTrsfPers.IsNull()
&& myChartTrsfPers->IsTrihedronOr2d())
{
if ((myChartTrsfPers->Corner2d() & Aspect_TOTP_LEFT) != 0)
{
anOffset.x() = 0;
}
else if ((myChartTrsfPers->Corner2d() & Aspect_TOTP_RIGHT) != 0)
{
anOffset.x() = -aCharSize.x();
}
else
{
anOffset.x() = -aCharSize.x() / 2;
}
if ((myChartTrsfPers->Corner2d() & Aspect_TOTP_BOTTOM) != 0)
{
anOffset.y() = aCharSize.y();
}
else if ((myChartTrsfPers->Corner2d() & Aspect_TOTP_TOP) != 0)
{
anOffset.y() = 0;
}
else
{
anOffset.y() = aCharSize.y() / 2;
}
}
Standard_Integer aVertLast = 1;
const bool isTopDown = false;
for (Standard_Integer aFrameIter = 0; aFrameIter < aNbBins; ++aFrameIter)
{
Standard_Integer aFrameIndex = aStats->DataFrames().Lower() + aStats->LastDataFrameIndex() + 1 + aFrameIter;
if (aFrameIndex > aStats->DataFrames().Upper())
{
aFrameIndex -= aNbBins;
}
const Graphic3d_FrameStatsData& aFrame = aStats->DataFrames().Value (aFrameIndex);
Standard_Real aTimeElapsed = 0.0;
Standard_Real aCurrY = 0.0;
for (Standard_Integer aTimerIter = 0; aTimerIter < aNbTimers; ++aTimerIter)
{
if (aTimers[aTimerIter] == Graphic3d_FrameStatsTimer_ElapsedFrame)
{
aTimeElapsed = aFrame.TimerValue (aTimers[aTimerIter]);
}
else
{
aTimeElapsed += aFrame.TimerValue (aTimers[aTimerIter]);
}
const Standard_Real aBinX1 = anOffset.x() + Standard_Real(aFrameIter) * aBinSize.x();
const Standard_Real aBinX2 = aBinX1 + aBinSize.x();
const Standard_Real aCurrSizeY = Min (aTimeElapsed / aMaxDuration, 1.2) * aBinSize.y();
const Standard_Real aBinY1 = isTopDown ? (anOffset.y() - aCurrY) : (anOffset.y() - aBinSize.y() + aCurrY);
const Standard_Real aBinY2 = isTopDown ? (anOffset.y() - aCurrSizeY) : (anOffset.y() - aBinSize.y() + aCurrSizeY);
myChartArray->SetVertice (aVertLast + 0, gp_Pnt (aBinX1, aBinY2, 0.0));
myChartArray->SetVertice (aVertLast + 1, gp_Pnt (aBinX1, aBinY1, 0.0));
myChartArray->SetVertice (aVertLast + 2, gp_Pnt (aBinX2, aBinY1, 0.0));
myChartArray->SetVertice (aVertLast + 3, gp_Pnt (aBinX2, aBinY2, 0.0));
if (toFillEdges)
{
const Graphic3d_Vec4ub& aTimerColor = aColors[aTimerIter];
myChartArray->SetVertexColor (aVertLast + 0, aTimerColor);
myChartArray->SetVertexColor (aVertLast + 1, aTimerColor);
myChartArray->SetVertexColor (aVertLast + 2, aTimerColor);
myChartArray->SetVertexColor (aVertLast + 3, aTimerColor);
myChartArray->AddEdges (aVertLast + 0, aVertLast + 1, aVertLast + 3);
myChartArray->AddEdges (aVertLast + 1, aVertLast + 2, aVertLast + 3);
}
aVertLast += 4;
if (aTimers[aTimerIter] == Graphic3d_FrameStatsTimer_ElapsedFrame)
{
aTimeElapsed = 0.0;
aCurrY = 0.0;
}
else
{
aCurrY = aCurrSizeY;
}
}
}
myChartVertices->init (aCtx,
myChartArray->Attributes()->Stride,
myChartArray->Attributes()->NbElements,
myChartArray->Attributes()->Data(),
GL_UNSIGNED_BYTE,
myChartArray->Attributes()->Stride);
if (myChartArray->Indices()->Stride == 2)
{
myChartIndices ->Init (aCtx,
1,
myChartArray->Indices()->NbElements,
(const GLushort* )myChartArray->Indices()->Data());
}
else if (myChartArray->Indices()->Stride == 4)
{
myChartIndices ->Init (aCtx,
1,
myChartArray->Indices()->NbElements,
(const GLuint* )myChartArray->Indices()->Data());
}
{
const Graphic3d_Vec4ub aWhite (255, 255, 255, 255);
const OpenGl_Vec3Vec4ub aLines[4] =
{
{ Graphic3d_Vec3((float )anOffset.x(), (float )anOffset.y(), 0.0f), aWhite },
{ Graphic3d_Vec3(float(anOffset.x() + aCharSize.x()), (float )anOffset.y(), 0.0f), aWhite },
{ Graphic3d_Vec3((float )anOffset.x(), float(anOffset.y() - aBinSize.y()), 0.0f), aWhite },
{ Graphic3d_Vec3(float(anOffset.x() + aCharSize.x()), float(anOffset.y() - aBinSize.y()),+ 0.0f), aWhite },
};
myChartLines->init (aCtx, sizeof(OpenGl_Vec3Vec4ub), 4, aLines, GL_UNSIGNED_BYTE, sizeof(OpenGl_Vec3Vec4ub));
}
{
OpenGl_TextParam aParams;
aParams.Height = aRendParams.StatsTextHeight;
aParams.HAlign = (!myChartTrsfPers.IsNull()
&& myChartTrsfPers->IsTrihedronOr2d()
&& (myChartTrsfPers->Corner2d() & Aspect_TOTP_RIGHT) != 0)
? Graphic3d_HTA_RIGHT
: Graphic3d_HTA_LEFT;
aParams.VAlign = Graphic3d_VTA_CENTER;
TCollection_AsciiString aLabels[3] =
{
TCollection_AsciiString() + 0 + " ms",
formatTimeMs(aMaxDuration * 0.5),
formatTimeMs(aMaxDuration)
};
const float aLabX = aParams.HAlign == Graphic3d_HTA_RIGHT
? float(anOffset.x())
: float(anOffset.x() + aCharSize.x());
myChartLabels[0].Init (aCtx, aLabels[isTopDown ? 0 : 2].ToCString(), OpenGl_Vec3 (aLabX, float(anOffset.y()), 0.0f), aParams);
myChartLabels[1].Init (aCtx, aLabels[isTopDown ? 1 : 1].ToCString(), OpenGl_Vec3 (aLabX, float(anOffset.y() - aBinSize.y() / 2), 0.0f), aParams);
myChartLabels[2].Init (aCtx, aLabels[isTopDown ? 2 : 0].ToCString(), OpenGl_Vec3 (aLabX, float(anOffset.y() - aBinSize.y()), 0.0f), aParams);
}
}
// =======================================================================
@ -114,28 +358,75 @@ void OpenGl_FrameStatsPrs::Render (const Handle(OpenGl_Workspace)& theWorkspace)
glDepthMask (GL_FALSE);
}
const OpenGl_AspectText* aTextAspectBack = theWorkspace->SetAspectText (&myTextAspect);
aCtx->ModelWorldState.Push();
aCtx->ModelWorldState.ChangeCurrent().InitIdentity();
aCtx->WorldViewState.Push();
OpenGl_Mat4& aWorldView = aCtx->WorldViewState.ChangeCurrent();
if (!myTrsfPers.IsNull())
// draw counters
{
myTrsfPers->Apply (theWorkspace->View()->Camera(),
aCtx->ProjectionState.Current(), aWorldView,
aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);
aCtx->WorldViewState.Push();
if (!myCountersTrsfPers.IsNull())
{
myCountersTrsfPers->Apply (theWorkspace->View()->Camera(),
aCtx->ProjectionState.Current(), aCtx->WorldViewState.ChangeCurrent(),
aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);
}
aCtx->ApplyModelViewMatrix();
myCountersText.Render (theWorkspace);
aCtx->WorldViewState.Pop();
}
aCtx->ApplyModelViewMatrix();
// draw chart
if (myChartIndices->IsValid()
&& myChartIndices->GetElemsNb() > 0)
{
aCtx->WorldViewState.Push();
if (!myChartTrsfPers.IsNull())
{
myChartTrsfPers->Apply (theWorkspace->View()->Camera(),
aCtx->ProjectionState.Current(), aCtx->WorldViewState.ChangeCurrent(),
aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);
}
aCtx->ApplyModelViewMatrix();
const OpenGl_AspectText* aTextAspectBack = theWorkspace->SetAspectText (&myTextAspect);
OpenGl_Text::Render (theWorkspace);
theWorkspace->SetAspectText (aTextAspectBack);
aCtx->ShaderManager()->BindFaceProgram (Handle(OpenGl_TextureSet)(), Graphic3d_TOSM_UNLIT,
Graphic3d_AlphaMode_Blend, true, false,
Handle(OpenGl_ShaderProgram)());
aCtx->SetColor4fv (OpenGl_Vec4 (1.0f, 1.0f, 1.0f, 1.0f));
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
myChartVertices->Bind (aCtx);
myChartVertices->bindAttribute (aCtx, Graphic3d_TOA_POS, 3, GL_FLOAT, myChartVertices->GetComponentsNb(), NULL);
myChartVertices->bindAttribute (aCtx, Graphic3d_TOA_COLOR, 4, GL_UNSIGNED_BYTE, myChartVertices->GetComponentsNb(), (void* )sizeof(Graphic3d_Vec3));
myChartIndices->Bind (aCtx);
aCtx->core15fwd->glDrawElements (GL_TRIANGLES, myChartIndices->GetElemsNb(), myChartIndices->GetDataType(), NULL);
myChartIndices->Unbind (aCtx);
myChartVertices->Unbind (aCtx);
myChartVertices->unbindAttribute (aCtx, Graphic3d_TOA_COLOR);
myChartVertices->unbindAttribute (aCtx, Graphic3d_TOA_POS);
glDisable (GL_BLEND);
myChartLines->Bind (aCtx);
myChartLines->bindAttribute (aCtx, Graphic3d_TOA_POS, 3, GL_FLOAT, myChartLines->GetComponentsNb(), NULL);
myChartLines->bindAttribute (aCtx, Graphic3d_TOA_COLOR, 4, GL_UNSIGNED_BYTE, myChartLines->GetComponentsNb(), (void* )sizeof(Graphic3d_Vec3));
aCtx->core15fwd->glDrawArrays (GL_LINES, 0, myChartLines->GetElemsNb());
myChartLines->Unbind (aCtx);
myChartLines->unbindAttribute (aCtx, Graphic3d_TOA_COLOR);
myChartLines->unbindAttribute (aCtx, Graphic3d_TOA_POS);
myChartLabels[0].Render (theWorkspace);
myChartLabels[1].Render (theWorkspace);
myChartLabels[2].Render (theWorkspace);
aCtx->WorldViewState.Pop();
}
aCtx->WorldViewState.Pop();
aCtx->ModelWorldState.Pop();
aCtx->ApplyWorldViewMatrix();
theWorkspace->SetAspectText (aTextAspectBack);
if (theWorkspace->UseDepthWrite() != wasEnabledDepth)
{
theWorkspace->UseDepthWrite() = wasEnabledDepth;

View File

@ -17,10 +17,13 @@
#include <OpenGl_FrameStats.hxx>
#include <OpenGl_Text.hxx>
class Graphic3d_ArrayOfTriangles;
class Graphic3d_TransformPers;
class OpenGl_IndexBuffer;
class OpenGl_VertexBuffer;
//! Element rendering frame statistics.
class OpenGl_FrameStatsPrs : public OpenGl_Text
class OpenGl_FrameStatsPrs : public OpenGl_Element
{
public:
@ -44,9 +47,21 @@ public:
protected:
OpenGl_AspectText myTextAspect; //!< text aspect
Handle(Graphic3d_TransformPers) myTrsfPers; //!< transformation persistence
Handle(OpenGl_FrameStats) myStatsPrev; //!< currently displayed stats
//! Update chart presentation.
Standard_EXPORT void updateChart (const Handle(OpenGl_Workspace)& theWorkspace);
protected:
Handle(OpenGl_FrameStats) myStatsPrev; //!< currently displayed stats
Handle(Graphic3d_TransformPers) myCountersTrsfPers; //!< transformation persistence for counters presentation
OpenGl_Text myCountersText; //!< counters presentation
OpenGl_AspectText myTextAspect; //!< text aspect
Handle(Graphic3d_TransformPers) myChartTrsfPers; //!< transformation persistence for chart presentation
Handle(Graphic3d_ArrayOfTriangles) myChartArray; //!< array of chart triangles
Handle(OpenGl_VertexBuffer) myChartVertices; //!< VBO with chart triangles
Handle(OpenGl_IndexBuffer) myChartIndices; //!< VBO with chart triangle indexes
Handle(OpenGl_VertexBuffer) myChartLines; //!< array of chart lines
OpenGl_Text myChartLabels[3]; //!< chart labels
};

View File

@ -514,6 +514,10 @@ void OpenGl_LayerList::SetLayerSettings (const Graphic3d_ZLayerId theLaye
void OpenGl_LayerList::UpdateCulling (const Handle(OpenGl_Workspace)& theWorkspace,
const Standard_Boolean theToDrawImmediate)
{
const Handle(OpenGl_FrameStats)& aStats = theWorkspace->GetGlContext()->FrameStats();
OSD_Timer& aTimer = aStats->ActiveDataFrame().ChangeTimer (Graphic3d_FrameStatsTimer_CpuCulling);
aTimer.Start();
const Standard_Integer aViewId = theWorkspace->View()->Identification();
const OpenGl_BVHTreeSelector& aSelector = theWorkspace->View()->BVHTreeSelector();
for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
@ -526,6 +530,9 @@ void OpenGl_LayerList::UpdateCulling (const Handle(OpenGl_Workspace)& theWorkspa
aLayer.UpdateCulling (aViewId, aSelector, theWorkspace->IsCullingEnabled());
}
aTimer.Stop();
aStats->ActiveDataFrame()[Graphic3d_FrameStatsTimer_CpuCulling] = aTimer.UserTimeCPU();
}
//=======================================================================

View File

@ -47,6 +47,9 @@ public:
const OpenGl_TextParam& theParams,
const bool theHasOwnAnchor = true);
//! Destructor
Standard_EXPORT virtual ~OpenGl_Text();
//! Setup new string and position
Standard_EXPORT void Init (const Handle(OpenGl_Context)& theCtx,
const Standard_Utf8Char* theText,
@ -68,6 +71,12 @@ public:
Standard_EXPORT virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const;
Standard_EXPORT virtual void Release (OpenGl_Context* theContext);
//! Return defined text.
const NCollection_String& Text() const { return myString; }
//! Return text formatting parameters.
const OpenGl_TextParam& FormatParams() const { return myParams; }
public: //! @name methods for compatibility with layers
//! Empty constructor
@ -108,9 +117,6 @@ public: //! @name methods for compatibility with layers
protected:
//! Destructor
Standard_EXPORT virtual ~OpenGl_Text();
friend class OpenGl_Trihedron;
friend class OpenGl_GraduatedTrihedron;

View File

@ -312,7 +312,7 @@ public:
const OpenGl_LayerList& LayerList() const { return myZLayers; }
//! Returns OpenGL window implementation.
const Handle(OpenGl_Window) GlWindow() const { return myWindow; }
const Handle(OpenGl_Window)& GlWindow() const { return myWindow; }
//! Returns OpenGL environment map.
const Handle(OpenGl_TextureSet)& GlTextureEnv() const { return myTextureEnv; }

View File

@ -166,7 +166,7 @@ void OpenGl_View::Redraw()
const Graphic3d_StereoMode aStereoMode = myRenderParams.StereoMode;
Graphic3d_Camera::Projection aProjectType = myCamera->ProjectionType();
Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
aCtx->FrameStats()->FrameStart (myWorkspace);
aCtx->FrameStats()->FrameStart (myWorkspace->View(), false);
// release pending GL resources
aCtx->ReleaseDelayed();
@ -566,7 +566,7 @@ void OpenGl_View::Redraw()
// reset render mode state
aCtx->FetchState();
aCtx->FrameStats()->FrameEnd (myWorkspace);
aCtx->FrameStats()->FrameEnd (myWorkspace->View(), false);
myWasRedrawnGL = Standard_True;
}
@ -592,7 +592,7 @@ void OpenGl_View::RedrawImmediate()
const Graphic3d_StereoMode aStereoMode = myRenderParams.StereoMode;
Graphic3d_Camera::Projection aProjectType = myCamera->ProjectionType();
OpenGl_FrameBuffer* aFrameBuffer = myFBO.operator->();
aCtx->FrameStats()->FrameStart (myWorkspace);
aCtx->FrameStats()->FrameStart (myWorkspace->View(), true);
if ( aFrameBuffer == NULL
&& !aCtx->DefaultFrameBuffer().IsNull()
@ -733,7 +733,7 @@ void OpenGl_View::RedrawImmediate()
{
aCtx->core11fwd->glFlush();
}
aCtx->FrameStats()->FrameEnd (myWorkspace);
aCtx->FrameStats()->FrameEnd (myWorkspace->View(), true);
myWasRedrawnGL = Standard_True;
}

View File

@ -10174,10 +10174,17 @@ static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theVa
else if (aVal == "mem"
|| aVal == "gpumem"
|| aVal == "estimmem") aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
else if (aVal == "skipimmediate"
|| aVal == "noimmediate") aFlag = Graphic3d_RenderingParams::PerfCounters_SkipImmediate;
else if (aVal == "frametime"
|| aVal == "frametimers"
|| aVal == "time") aFlag = Graphic3d_RenderingParams::PerfCounters_FrameTime;
else if (aVal == "basic") aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
else if (aVal == "extended"
|| aVal == "verbose"
|| aVal == "extra") aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
else if (aVal == "full"
|| aVal == "all") aFlag = Graphic3d_RenderingParams::PerfCounters_All;
else
{
return Standard_False;
@ -10363,6 +10370,14 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
{
theDI << " gpumem";
}
if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
{
theDI << " frameTime";
}
if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
{
theDI << " skipimmediate";
}
if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
{
theDI << " none";
@ -11024,6 +11039,26 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
}
aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
}
else if (aFlag == "-perfchart"
|| aFlag == "-statschart")
{
if (++anArgIter >= theArgNb)
{
std::cout << "Error: wrong syntax at argument '" << anArg << "'\n";
return 1;
}
aView->ChangeRenderingParams().StatsNbFrames = Draw::Atoi (theArgVec[anArgIter]);
}
else if (aFlag == "-perfchartmax"
|| aFlag == "-statschartmax")
{
if (++anArgIter >= theArgNb)
{
std::cout << "Error: wrong syntax at argument '" << anArg << "'\n";
return 1;
}
aView->ChangeRenderingParams().StatsMaxChartTime = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
}
else
{
std::cout << "Error: wrong syntax, unknown flag '" << anArg << "'\n";
@ -12542,9 +12577,12 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
"\n '-exposure value' Exposure value for tone mapping (0.0 value disables the effect)"
"\n '-whitepoint value' White point value for filmic tone mapping"
"\n '-tonemapping mode' Tone mapping mode (disabled, filmic)"
"\n '-perfCounters none|fps|cpu|layers|structures|groups|arrays|triagles|points|gpuMem|basic|extended|nofps'"
"\n '-perfCounters none|fps|cpu|layers|structures|groups|arrays|triagles|points"
"\n ' |gpuMem|frameTime|basic|extended|full|nofps|skipImmediate'"
"\n Show/hide performance counters (flags can be combined)"
"\n '-perfUpdateInterval nbSeconds' Performance counters update interval"
"\n '-perfChart nbFrames' Show frame timers chart limited by specified number of frames"
"\n '-perfChartMax seconds' Maximum time in seconds with the chart"
"\n Unlike vcaps, these parameters dramatically change visual properties."
"\n Command is intended to control presentation quality depending on"
"\n hardware capabilities and performance.",