mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-08-24 19:36:05 +08:00
6c24544fe1
- Refactor boolean expressions and improve code readability across multiple files - Simplified boolean expressions by removing unnecessary comparisons to true/false. - Replaced explicit boolean checks with direct variable usage Used flags: readability-static-accessed-through-instance readability-simplify-boolean-expr performance-for-range-copy performance-move-const-arg misc-unused-parameters misc-redundant-expression
815 lines
29 KiB
C++
815 lines
29 KiB
C++
// 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,
|
|
int theWidth,
|
|
const char* thePrefix,
|
|
size_t theValue,
|
|
const char* thePostfix = nullptr)
|
|
{
|
|
if (thePrefix != nullptr)
|
|
{
|
|
theStream << thePrefix;
|
|
}
|
|
theStream << std::setfill(' ') << std::setw(theWidth);
|
|
if (theValue >= 1000000000)
|
|
{
|
|
double aValM = double(theValue) / 1000000000.0;
|
|
theStream << std::fixed << std::setprecision(1) << aValM << "G";
|
|
}
|
|
else if (theValue >= 1000000)
|
|
{
|
|
double aValM = double(theValue) / 1000000.0;
|
|
theStream << std::fixed << std::setprecision(1) << aValM << "M";
|
|
}
|
|
else if (theValue >= 1000)
|
|
{
|
|
double aValK = double(theValue) / 1000.0;
|
|
theStream << std::fixed << std::setprecision(1) << aValK << "k";
|
|
}
|
|
else
|
|
{
|
|
theStream << theValue;
|
|
if (thePostfix == nullptr)
|
|
{
|
|
theStream << " ";
|
|
}
|
|
}
|
|
if (thePostfix != nullptr)
|
|
{
|
|
theStream << thePostfix;
|
|
}
|
|
return theStream;
|
|
}
|
|
|
|
//! Format a pair of counters.
|
|
static std::ostream& formatCounterPair(std::ostream& theStream,
|
|
int theWidth,
|
|
const char* thePrefix,
|
|
size_t theValue,
|
|
size_t theImmValue,
|
|
bool theToShowImmediate)
|
|
{
|
|
formatCounter(theStream, theWidth, thePrefix, theValue, nullptr);
|
|
if (theToShowImmediate)
|
|
{
|
|
formatCounter(theStream, 1, "(", theImmValue, ")");
|
|
}
|
|
theStream << "\n";
|
|
return theStream;
|
|
}
|
|
|
|
//! Format memory counter.
|
|
static std::ostream& formatBytes(std::ostream& theStream,
|
|
int theWidth,
|
|
const char* thePrefix,
|
|
size_t theValue,
|
|
const char* thePostfix = nullptr)
|
|
{
|
|
if (thePrefix != nullptr)
|
|
{
|
|
theStream << thePrefix;
|
|
}
|
|
theStream << std::setfill(' ') << std::setw(theWidth);
|
|
if (theValue >= 1024 * 1024 * 1024)
|
|
{
|
|
double aValM = double(theValue) / (1024.0 * 1024.0 * 1024.0);
|
|
theStream << std::fixed << std::setprecision(1) << aValM << " GiB";
|
|
}
|
|
else if (theValue >= 1024 * 1024)
|
|
{
|
|
double aValM = double(theValue) / (1024.0 * 1024.0);
|
|
theStream << std::fixed << std::setprecision(1) << aValM << " MiB";
|
|
}
|
|
else if (theValue >= 1024)
|
|
{
|
|
double aValK = double(theValue) / 1024.0;
|
|
theStream << std::fixed << std::setprecision(1) << aValK << " KiB";
|
|
}
|
|
else
|
|
{
|
|
theStream << theValue << " B";
|
|
}
|
|
if (thePostfix != nullptr)
|
|
{
|
|
theStream << thePostfix;
|
|
}
|
|
return theStream;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
constexpr double THE_SECONDS_IN_HOUR = 3600.0;
|
|
constexpr double THE_SECONDS_IN_MINUTE = 60.0;
|
|
constexpr double THE_SECOND_IN_HOUR = 1.0 / THE_SECONDS_IN_HOUR;
|
|
constexpr double THE_SECOND_IN_MINUTE = 1.0 / THE_SECONDS_IN_MINUTE;
|
|
} // namespace
|
|
|
|
//! Format time.
|
|
static std::ostream& formatTime(std::ostream& theStream,
|
|
int theWidth,
|
|
const char* thePrefix,
|
|
double theSeconds,
|
|
const char* thePostfix = nullptr)
|
|
{
|
|
if (thePrefix != nullptr)
|
|
{
|
|
theStream << thePrefix;
|
|
}
|
|
|
|
double aSecIn = theSeconds;
|
|
unsigned int aHours = (unsigned int)(aSecIn * THE_SECOND_IN_HOUR);
|
|
aSecIn -= double(aHours) * THE_SECONDS_IN_HOUR;
|
|
unsigned int aMinutes = (unsigned int)(aSecIn * THE_SECOND_IN_MINUTE);
|
|
aSecIn -= double(aMinutes) * THE_SECONDS_IN_MINUTE;
|
|
unsigned int aSeconds = (unsigned int)aSecIn;
|
|
aSecIn -= double(aSeconds);
|
|
double 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 != nullptr)
|
|
{
|
|
theStream << thePostfix;
|
|
}
|
|
return theStream;
|
|
}
|
|
|
|
//! Add key-value pair to the dictionary.
|
|
static void addInfo(
|
|
NCollection_IndexedDataMap<TCollection_AsciiString, TCollection_AsciiString>& theDict,
|
|
const TCollection_AsciiString& theKey,
|
|
const char* theValue)
|
|
{
|
|
TCollection_AsciiString aValue(theValue != nullptr ? theValue : "");
|
|
theDict.ChangeFromIndex(theDict.Add(theKey, aValue)) = aValue;
|
|
}
|
|
|
|
//! Add key-value pair to the dictionary.
|
|
static void addInfo(
|
|
NCollection_IndexedDataMap<TCollection_AsciiString, TCollection_AsciiString>& theDict,
|
|
const TCollection_AsciiString& theKey,
|
|
const double theValue)
|
|
{
|
|
char aTmp[50];
|
|
Sprintf(aTmp, "%.1g", theValue);
|
|
addInfo(theDict, theKey, aTmp);
|
|
}
|
|
|
|
//! Add key-value pair to the dictionary.
|
|
static void addInfo(
|
|
NCollection_IndexedDataMap<TCollection_AsciiString, TCollection_AsciiString>& theDict,
|
|
const TCollection_AsciiString& theKey,
|
|
const size_t theValue)
|
|
{
|
|
char aTmp[50];
|
|
Sprintf(aTmp, "%zu", theValue);
|
|
addInfo(theDict, theKey, aTmp);
|
|
}
|
|
|
|
//! Format time.
|
|
static void addTimeInfo(
|
|
NCollection_IndexedDataMap<TCollection_AsciiString, TCollection_AsciiString>& theDict,
|
|
const TCollection_AsciiString& theKey,
|
|
double theSeconds)
|
|
{
|
|
double aSecIn = theSeconds;
|
|
unsigned int aHours = (unsigned int)(aSecIn * THE_SECOND_IN_HOUR);
|
|
aSecIn -= double(aHours) * THE_SECONDS_IN_HOUR;
|
|
unsigned int aMinutes = (unsigned int)(aSecIn * THE_SECOND_IN_MINUTE);
|
|
aSecIn -= double(aMinutes) * THE_SECONDS_IN_MINUTE;
|
|
unsigned int aSeconds = (unsigned int)aSecIn;
|
|
aSecIn -= double(aSeconds);
|
|
double aMilliSeconds = 1000.0 * aSecIn;
|
|
|
|
char aBuffer[64];
|
|
if (aHours > 0)
|
|
{
|
|
Sprintf(aBuffer, "%02u:%02u:%02u", aHours, aMinutes, aSeconds);
|
|
}
|
|
else if (aMinutes > 0)
|
|
{
|
|
Sprintf(aBuffer, "%02u:%02u", aMinutes, aSeconds);
|
|
}
|
|
else if (aSeconds > 0)
|
|
{
|
|
Sprintf(aBuffer, "%2u", aSeconds);
|
|
}
|
|
else
|
|
{
|
|
addInfo(theDict, theKey, aMilliSeconds);
|
|
return;
|
|
}
|
|
|
|
addInfo(theDict, theKey, aBuffer);
|
|
}
|
|
} // namespace
|
|
|
|
//=================================================================================================
|
|
|
|
Graphic3d_FrameStats::Graphic3d_FrameStats()
|
|
: myFpsTimer(true),
|
|
myFrameStartTime(0.0),
|
|
myFrameDuration(0.0),
|
|
myUpdateInterval(1.0),
|
|
myFpsFrameCount(0),
|
|
myCounters(0, 0),
|
|
myLastFrameIndex(0),
|
|
myIsLongLineFormat(false)
|
|
{
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Graphic3d_FrameStats::~Graphic3d_FrameStats() = default;
|
|
|
|
//=================================================================================================
|
|
|
|
TCollection_AsciiString Graphic3d_FrameStats::FormatStats(
|
|
Graphic3d_RenderingParams::PerfCounters theFlags) const
|
|
{
|
|
const int aValWidth = 5;
|
|
std::stringstream aBuf;
|
|
// clang-format off
|
|
const bool isCompact = theFlags == Graphic3d_RenderingParams::PerfCounters_FrameRate; // only FPS is displayed
|
|
// clang-format on
|
|
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();
|
|
if (aStats.ImmediateFrameRate() > 0.0)
|
|
{
|
|
aBuf << " (" << std::fixed << std::setprecision(1) << aStats.ImmediateFrameRate() << ")";
|
|
}
|
|
aBuf << "\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();
|
|
if (aStats.ImmediateFrameRateCpu() > 0.0)
|
|
{
|
|
aBuf << " (" << std::fixed << std::setprecision(1) << aStats.ImmediateFrameRateCpu() << ")";
|
|
}
|
|
aBuf << "\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");
|
|
}
|
|
}
|
|
|
|
const bool hasImmediate =
|
|
aStats[Graphic3d_FrameStatsCounter_NbLayersImmediate] != 0 || aStats.ImmediateFrameRate() > 0.0;
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0
|
|
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0
|
|
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
|
|
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_Lines) != 0
|
|
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0
|
|
|| (!myIsLongLineFormat
|
|
&& ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
|
|
|| (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)))
|
|
{
|
|
if (hasImmediate)
|
|
{
|
|
aBuf << "Rendered (imm.)\n";
|
|
}
|
|
else
|
|
{
|
|
aBuf << "Rendered\n";
|
|
}
|
|
}
|
|
if (!myIsLongLineFormat && (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
|
|
{
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" Layers: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbLayersImmediate],
|
|
hasImmediate);
|
|
}
|
|
if (!myIsLongLineFormat && (theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
|
|
{
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" Structs: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbStructsImmediate],
|
|
hasImmediate);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
|
|
{
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" Groups: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbGroupsNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbGroupsImmediate],
|
|
hasImmediate);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
|
|
{
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" Arrays: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsImmediate],
|
|
hasImmediate);
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" [fill]: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsFillImmediate],
|
|
hasImmediate);
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" [line]: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsLineImmediate],
|
|
hasImmediate);
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" [point]: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsPointImmediate],
|
|
hasImmediate);
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" [text]: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsTextImmediate],
|
|
hasImmediate);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
|
|
{
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" Triangles: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbTrianglesImmediate],
|
|
hasImmediate);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
|
|
{
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" Lines: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbLinesNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbLinesImmediate],
|
|
hasImmediate);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
|
|
{
|
|
formatCounterPair(aBuf,
|
|
aValWidth,
|
|
" Points: ",
|
|
aStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled],
|
|
aStats[Graphic3d_FrameStatsCounter_NbPointsImmediate],
|
|
hasImmediate);
|
|
}
|
|
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());
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void Graphic3d_FrameStats::FormatStats(
|
|
NCollection_IndexedDataMap<TCollection_AsciiString, TCollection_AsciiString>& theDict,
|
|
Graphic3d_RenderingParams::PerfCounters theFlags) const
|
|
{
|
|
const Graphic3d_FrameStatsData& aStats = LastDataFrame();
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
|
|
{
|
|
addInfo(theDict, "FPS", aStats.FrameRate());
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
|
|
{
|
|
addInfo(theDict, "CPU FPS", aStats.FrameRateCpu());
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
|
|
{
|
|
addInfo(theDict, "Layers", aStats[Graphic3d_FrameStatsCounter_NbLayers]);
|
|
if (HasCulledLayers())
|
|
{
|
|
addInfo(theDict, "Rendered layers", aStats[Graphic3d_FrameStatsCounter_NbLayersNotCulled]);
|
|
}
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
|
|
{
|
|
addInfo(theDict, "Structs", aStats[Graphic3d_FrameStatsCounter_NbStructs]);
|
|
if (HasCulledStructs())
|
|
{
|
|
addInfo(theDict, "Rendered structs", aStats[Graphic3d_FrameStatsCounter_NbStructsNotCulled]);
|
|
}
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
|
|
{
|
|
addInfo(theDict, "Rendered groups", aStats[Graphic3d_FrameStatsCounter_NbGroupsNotCulled]);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
|
|
{
|
|
addInfo(theDict, "Rendered arrays", aStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled]);
|
|
addInfo(theDict,
|
|
"Rendered [fill] arrays",
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled]);
|
|
addInfo(theDict,
|
|
"Rendered [line] arrays",
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled]);
|
|
addInfo(theDict,
|
|
"Rendered [point] arrays",
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled]);
|
|
addInfo(theDict,
|
|
"Rendered [text] arrays",
|
|
aStats[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled]);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
|
|
{
|
|
addInfo(theDict,
|
|
"Rendered triangles",
|
|
aStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled]);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
|
|
{
|
|
addInfo(theDict, "Rendered lines", aStats[Graphic3d_FrameStatsCounter_NbLinesNotCulled]);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
|
|
{
|
|
addInfo(theDict, "Rendered points", aStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled]);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
|
|
{
|
|
addInfo(theDict,
|
|
"GPU Memory [geometry]",
|
|
aStats[Graphic3d_FrameStatsCounter_EstimatedBytesGeom]);
|
|
addInfo(theDict,
|
|
"GPU Memory [textures]",
|
|
aStats[Graphic3d_FrameStatsCounter_EstimatedBytesTextures]);
|
|
addInfo(theDict, "GPU Memory [frames]", aStats[Graphic3d_FrameStatsCounter_EstimatedBytesFbos]);
|
|
}
|
|
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
|
|
{
|
|
addTimeInfo(theDict, "Elapsed Frame (average)", aStats[Graphic3d_FrameStatsTimer_ElapsedFrame]);
|
|
addTimeInfo(theDict, "CPU Frame (average)", aStats[Graphic3d_FrameStatsTimer_CpuFrame]);
|
|
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
|
|
{
|
|
addTimeInfo(theDict, "CPU Picking (average)", aStats[Graphic3d_FrameStatsTimer_CpuPicking]);
|
|
}
|
|
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
|
|
{
|
|
addTimeInfo(theDict, "CPU Culling (average)", aStats[Graphic3d_FrameStatsTimer_CpuCulling]);
|
|
}
|
|
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
|
|
{
|
|
addTimeInfo(theDict, "CPU Dynamics (average)", aStats[Graphic3d_FrameStatsTimer_CpuDynamics]);
|
|
}
|
|
if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameTimeMax) != 0)
|
|
{
|
|
addTimeInfo(theDict, "CPU Frame (max)", myCountersMax[Graphic3d_FrameStatsTimer_CpuFrame]);
|
|
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking] > 0.0)
|
|
{
|
|
addTimeInfo(theDict,
|
|
"CPU Picking (max)",
|
|
myCountersMax[Graphic3d_FrameStatsTimer_CpuPicking]);
|
|
}
|
|
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling] > 0.0)
|
|
{
|
|
addTimeInfo(theDict,
|
|
"CPU Culling (max)",
|
|
myCountersMax[Graphic3d_FrameStatsTimer_CpuCulling]);
|
|
}
|
|
if (myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics])
|
|
{
|
|
addTimeInfo(theDict,
|
|
"CPU Dynamics (max)",
|
|
myCountersMax[Graphic3d_FrameStatsTimer_CpuDynamics]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void Graphic3d_FrameStats::FrameStart(const occ::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 int aNbFrames =
|
|
std::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;
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void Graphic3d_FrameStats::FrameEnd(const occ::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;
|
|
}
|
|
|
|
const Graphic3d_FrameStatsData& aPrevFrame = myCounters.Value(myLastFrameIndex);
|
|
if (aTime > gp::Resolution())
|
|
{
|
|
// update FPS
|
|
myFpsTimer.Stop();
|
|
const double aCpuSec = myFpsTimer.UserTimeCPU();
|
|
myCountersTmp[Graphic3d_FrameStatsTimer_ElapsedFrame] = aTime;
|
|
myCountersTmp[Graphic3d_FrameStatsTimer_CpuFrame] = aCpuSec;
|
|
|
|
if (theIsImmediateOnly)
|
|
{
|
|
myCountersTmp.ChangeImmediateFrameRate() = double(myFpsFrameCount) / aTime;
|
|
myCountersTmp.ChangeImmediateFrameRateCpu() =
|
|
aCpuSec > gp::Resolution() ? double(myFpsFrameCount) / aCpuSec : -1.0;
|
|
myCountersTmp.ChangeFrameRate() = aPrevFrame.FrameRate();
|
|
myCountersTmp.ChangeFrameRateCpu() = aPrevFrame.FrameRateCpu();
|
|
}
|
|
else
|
|
{
|
|
myCountersTmp.ChangeImmediateFrameRate() = -1.0;
|
|
myCountersTmp.ChangeImmediateFrameRateCpu() = -1.0;
|
|
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();
|
|
}
|
|
if (theIsImmediateOnly)
|
|
{
|
|
// copy rendered counters collected for immediate layers
|
|
const int anImmShift =
|
|
Graphic3d_FrameStatsCounter_IMMEDIATE_LOWER - Graphic3d_FrameStatsCounter_RENDERED_LOWER;
|
|
Standard_STATIC_ASSERT(
|
|
(Graphic3d_FrameStatsCounter_RENDERED_UPPER - Graphic3d_FrameStatsCounter_RENDERED_LOWER)
|
|
== (Graphic3d_FrameStatsCounter_IMMEDIATE_UPPER
|
|
- Graphic3d_FrameStatsCounter_IMMEDIATE_LOWER)) for (int aCntIter =
|
|
Graphic3d_FrameStatsCounter_RENDERED_LOWER;
|
|
aCntIter
|
|
<= Graphic3d_FrameStatsCounter_RENDERED_UPPER;
|
|
++aCntIter)
|
|
{
|
|
myCountersTmp.ChangeCounterValue((Graphic3d_FrameStatsCounter)(aCntIter + anImmShift)) =
|
|
myCountersTmp.CounterValue((Graphic3d_FrameStatsCounter)aCntIter);
|
|
}
|
|
|
|
// copy main rendered counters from previous non-immediate frame
|
|
for (int aCntIter = Graphic3d_FrameStatsCounter_RENDERED_LOWER;
|
|
aCntIter <= Graphic3d_FrameStatsCounter_RENDERED_UPPER;
|
|
++aCntIter)
|
|
{
|
|
myCountersTmp.ChangeCounterValue((Graphic3d_FrameStatsCounter)aCntIter) =
|
|
aPrevFrame.CounterValue((Graphic3d_FrameStatsCounter)aCntIter);
|
|
}
|
|
myCountersTmp.ChangeCounterValue(Graphic3d_FrameStatsCounter_EstimatedBytesGeom) =
|
|
aPrevFrame.CounterValue(Graphic3d_FrameStatsCounter_EstimatedBytesGeom);
|
|
}
|
|
myCounters.SetValue(myLastFrameIndex, myCountersTmp);
|
|
myCountersTmp.Reset();
|
|
}
|