1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00

0029346: Visualization, TKOpenGl - collect frame statistics [backported,

partially disabled; fixed frustum culling bug].

Graphic3d_RenderingParams::ToShowStats - new option displaying rendering statistics.

OpenGl_FrameStats - new class for accumulating frame statistics.
OpenGl_Context::FrameStats() provides an access to the frame stats
used for currently rendered context.
OpenGl_View::Redraw() and OpenGl_View::RedrawImmediate()
resets counters within OpenGl_Context::FrameStats().

OpenGl_Layer::UpdateCulling() - simplified resetting of culling state for cullable structures.

# Conflicts:
#	src/OpenGl/OpenGl_FrameBuffer.cxx
This commit is contained in:
kgv 2020-07-14 12:13:34 +03:00
parent 365585ddfb
commit 3d607bc062
36 changed files with 1447 additions and 107 deletions

@ -9,6 +9,8 @@ pload VISUALIZATION
vinit View1 w=1024 h=1024
vclear
vdefaults -autoTriang 0
vrenderparams -stats basic
# parameter NB defines number of spheres by each coordinate
set NB 10
@ -23,11 +25,12 @@ for {set i 0} {$i < $NB} {incr i} {
}
}
}
eval compound $slist c
incmesh c 0.006
puts "Measuring FPS of display of spheres as separate objects..."
vaxo
vsetdispmode 1
eval vdisplay $slist
eval vdisplay -dispMode 1 $slist
vfit
# measure FPS
@ -35,16 +38,14 @@ puts [set fps_separate [vfps]]
vclear
puts "Measuring FPS of display of spheres as single object..."
eval compound $slist c
vdisplay c
vdisplay -dispMode 1 c
# measure FPS
puts [set fps_compound [vfps]]
vclear
# redisplay individual spheres, trying to avoid unnecessary internal updates
#vfrustumculling 0 ;# try to disable updates of frustum culling structures
eval vdisplay -mutable $slist
eval vdisplay -dispMode 1 $slist
# auxiliary procedure to make random update of variable
proc upd {theValueName theDeltaName theTime theToRand} {
@ -69,8 +70,10 @@ proc animateSpheres {{theDuration 10.0}} {
for {set i 0} {$i < $::NB} {incr i $nb} {
for {set j 0} {$j < $::NB} {incr j $nb} {
for {set k 0} {$k < $::NB} {incr k $nb} {
# mark animated spheres mutable for faster updates
uplevel #0 vdisplay -dispMode 1 -mutable s$i$j$k
# vaspects -noupdate s$i$j$k -setcolor red -setmaterial plastic
vaspects -noupdate s$i$j$k -setcolor red
uplevel #0 vaspects -noupdate s$i$j$k -setcolor red
set x$i$j$k 0.0
set y$i$j$k 0.0
set z$i$j$k 0.0

@ -16,7 +16,8 @@
#ifndef _Graphic3d_RenderingParams_HeaderFile
#define _Graphic3d_RenderingParams_HeaderFile
#include <Graphic3d_Mat4.hxx>
#include <Graphic3d_AspectText3d.hxx>
#include <Graphic3d_TransformPers.hxx>
#include <Graphic3d_RenderTransparentMethod.hxx>
#include <Graphic3d_RenderingMode.hxx>
#include <Graphic3d_StereoMode.hxx>
@ -44,6 +45,31 @@ public:
Anaglyph_UserDefined //!< use externally specified matrices
};
//! Statistics display flags.
enum PerfCounters
{
PerfCounters_NONE = 0x000, //!< no stats
PerfCounters_FrameRate = 0x001, //!< Frame Rate
PerfCounters_CPU = 0x002, //!< CPU utilization
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)
//
PerfCounters_Groups = 0x010, //!< count primitive Groups (1 Structure holds 1 or more primitive Group)
PerfCounters_GroupArrays = 0x020, //!< count Arrays within Primitive Groups (optimal primitive Group holds 1 Array)
//
PerfCounters_Triangles = 0x040, //!< count Triangles
PerfCounters_Points = 0x080, //!< count Points
//
PerfCounters_EstimMem = 0x100, //!< estimated GPU memory usage
//! show basic statistics
PerfCounters_Basic = PerfCounters_FrameRate | PerfCounters_CPU | PerfCounters_Layers | PerfCounters_Structures,
//! extended (verbose) statistics
PerfCounters_Extended = PerfCounters_Basic
| PerfCounters_Groups | PerfCounters_GroupArrays
| PerfCounters_Triangles | PerfCounters_Points
| PerfCounters_EstimMem,
};
public:
//! Creates default rendering parameters.
@ -78,7 +104,14 @@ public:
StereoMode (Graphic3d_StereoMode_QuadBuffer),
AnaglyphFilter (Anaglyph_RedCyan_Optimized),
ToReverseStereo (Standard_False),
//
StatsPosition (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i (20, 20))),
StatsTextAspect (new Graphic3d_AspectText3d()),
StatsUpdateInterval (1.0),
StatsTextHeight (16),
CollectedStats (PerfCounters_Basic),
ToShowStats (Standard_False),
//
Resolution (THE_DEFAULT_RESOLUTION)
{
const Graphic3d_Vec4 aZero (0.0f, 0.0f, 0.0f, 0.0f);
@ -90,6 +123,13 @@ public:
AnaglyphRight.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
AnaglyphRight.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
AnaglyphRight.SetRow (3, aZero);
StatsTextAspect->SetColor (Quantity_NOC_WHITE);
StatsTextAspect->SetColorSubTitle (Quantity_NOC_BLACK);
StatsTextAspect->SetFont (Font_NOF_ASCII_MONO);
///StatsTextAspect->SetDisplayType (Aspect_TODT_SHADOW);
StatsTextAspect->SetTextZoomable (Standard_False);
StatsTextAspect->SetTextFontAspect (Font_FA_Regular);
}
//! Returns resolution ratio.
@ -136,6 +176,20 @@ public:
Graphic3d_Mat4 AnaglyphRight; //!< right anaglyph filter (in normalized colorspace), Color = AnaglyphRight * theColorRight + AnaglyphLeft * theColorLeft;
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_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
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)
Standard_Boolean ToShowStats; //!< display performance statistics, FALSE by default;
//! note that counters specified within CollectedStats will be updated nevertheless
//! of visibility of widget managed by ToShowStats flag (e.g. stats can be retrieved by application for displaying using other methods)
unsigned int Resolution; //!< Pixels density (PPI), defines scaling factor for parameters like text size
//! (when defined in screen-space units rather than in 3D) to be properly displayed
//! on device (screen / printer). 72 is default value.

@ -13,6 +13,10 @@ OpenGl_AspectMarker.cxx
OpenGl_AspectMarker.hxx
OpenGl_AspectText.cxx
OpenGl_AspectText.hxx
OpenGl_FrameStats.cxx
OpenGl_FrameStats.hxx
OpenGl_FrameStatsPrs.cxx
OpenGl_FrameStatsPrs.hxx
OpenGl_Group.hxx
OpenGl_Group.cxx
OpenGl_Structure.hxx

@ -63,6 +63,9 @@ public:
//! Returns the structure corresponding to the given ID.
const OpenGl_Structure* GetStructureById (Standard_Integer theId);
//! Access directly a collection of structures.
const NCollection_IndexedMap<const OpenGl_Structure*>& Structures() const { return myStructs; }
private:
NCollection_IndexedMap<const OpenGl_Structure*> myStructs; //!< Indexed map of structures.

@ -69,6 +69,9 @@ public:
//! Returns the structure corresponding to the given ID.
const OpenGl_Structure* GetStructureById (Standard_Integer theId);
//! Access directly a collection of structures.
const NCollection_IndexedMap<const OpenGl_Structure*>& Structures() const { return myStructs; }
//! Marks object state as outdated (needs BVH rebuilding).
void MarkDirty()
{

@ -54,6 +54,9 @@ public:
//! @param theContext [in] the resource context.
Standard_EXPORT virtual void Release (OpenGl_Context* theContext) Standard_OVERRIDE;
//! Returns estimated GPU memory usage - not implemented.
virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE { return 0; }
//! Return parent clipping plane structure.
const Handle(Graphic3d_ClipPlane)& Plane() const { return myPlaneRoot; }

@ -28,6 +28,7 @@
#include <OpenGl_ArbTexBindless.hxx>
#include <OpenGl_GlCore44.hxx>
#include <OpenGl_FrameBuffer.hxx>
#include <OpenGl_FrameStats.hxx>
#include <OpenGl_Sampler.hxx>
#include <OpenGl_ShaderManager.hxx>
#include <OpenGl_Workspace.hxx>
@ -174,6 +175,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
myHasRayTracing (Standard_False),
myHasRayTracingTextures (Standard_False),
myHasRayTracingAdaptiveSampling (Standard_False),
myFrameStats (new OpenGl_FrameStats()),
#if !defined(GL_ES_VERSION_2_0)
myPointSpriteOrig (GL_UPPER_LEFT),
myRenderMode (GL_RENDER),

@ -138,6 +138,7 @@ class OpenGl_FrameBuffer;
class OpenGl_Sampler;
class OpenGl_ShaderProgram;
class OpenGl_ShaderManager;
class OpenGl_FrameStats;
enum OpenGl_FeatureFlag
{
@ -200,6 +201,8 @@ class OpenGl_Context : public Standard_Transient
friend class OpenGl_Window;
public:
typedef NCollection_Shared< NCollection_DataMap<TCollection_AsciiString, Handle(OpenGl_Resource)> > OpenGl_ResourcesMap;
//! Function for getting power of to number larger or equal to input number.
//! @param theNumber number to 'power of two'
//! @param theThreshold upper threshold
@ -444,6 +447,9 @@ public:
//! Clean up the delayed release queue.
Standard_EXPORT void ReleaseDelayed();
//! Return map of shared resources.
const OpenGl_ResourcesMap& SharedResources() const { return *mySharedResources; }
//! @return tool for management of clippings within this context.
inline OpenGl_Clipping& ChangeClipping() { return myClippingState; }
@ -590,6 +596,9 @@ public:
public: //! @name methods to alter or retrieve current state
//! Return structure holding frame statistics.
const Handle(OpenGl_FrameStats)& FrameStats() const { return myFrameStats; }
//! Return cached viewport definition (x, y, width, height).
const Standard_Integer* Viewport() const { return myViewport; }
@ -868,7 +877,6 @@ private: // system-dependent fields
private: // context info
typedef NCollection_Shared< NCollection_DataMap<TCollection_AsciiString, Standard_Integer> > OpenGl_DelayReleaseMap;
typedef NCollection_Shared< NCollection_DataMap<TCollection_AsciiString, Handle(OpenGl_Resource)> > OpenGl_ResourcesMap;
typedef NCollection_Shared< NCollection_List<Handle(OpenGl_Resource)> > OpenGl_ResourcesStack;
typedef NCollection_SparseArray<Standard_Integer> OpenGl_DrawBuffers;
@ -904,6 +912,7 @@ private: // context info
private: //! @name fields tracking current state
Handle(OpenGl_FrameStats) myFrameStats; //!< structure accumulating frame statistics
Handle(OpenGl_ShaderProgram) myActiveProgram; //!< currently active GLSL program
Handle(OpenGl_TextureSet) myActiveTextures; //!< currently bound textures
//!< currently active sampler objects

@ -76,6 +76,20 @@ void OpenGl_Font::Release (OpenGl_Context* theCtx)
myTextures.Clear();
}
// =======================================================================
// function : EstimatedDataSize
// purpose :
// =======================================================================
Standard_Size OpenGl_Font::EstimatedDataSize() const
{
Standard_Size aSize = 0;
for (NCollection_Vector<Handle(OpenGl_Texture)>::Iterator aTexIter (myTextures); aTexIter.More(); aTexIter.Next())
{
aSize += aTexIter.Value()->EstimatedDataSize();
}
return aSize;
}
// =======================================================================
// function : Init
// purpose :

@ -61,6 +61,9 @@ public:
//! Destroy object - will release GPU memory if any
Standard_EXPORT virtual void Release (OpenGl_Context* theCtx) Standard_OVERRIDE;
//! Returns estimated GPU memory usage.
Standard_EXPORT virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE;
//! @return key of shared resource
inline const TCollection_AsciiString& ResourceKey() const
{

@ -818,3 +818,35 @@ void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
}
}
// =======================================================================
// function : EstimatedDataSize
// purpose :
// =======================================================================
Standard_Size OpenGl_FrameBuffer::EstimatedDataSize() const
{
if (!IsValid())
{
return 0;
}
Standard_Size aSize = 0;
for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
{
aSize += aTextureIt.Value()->EstimatedDataSize();
}
if (!myDepthStencilTexture.IsNull())
{
aSize += myDepthStencilTexture->EstimatedDataSize();
}
if (myGlColorRBufferId != NO_RENDERBUFFER
&& !myColorFormats.IsEmpty())
{
aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myColorFormats.First()) * myInitVPSizeX * myInitVPSizeY;
}
if (myGlDepthRBufferId != NO_RENDERBUFFER)
{
aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myDepthFormat) * myInitVPSizeX * myInitVPSizeY;
}
return aSize;
}

@ -245,6 +245,9 @@ public:
return myGlDepthRBufferId;
}
//! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules.
Standard_EXPORT virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE;
protected:
Standard_Boolean isValidFrameBuffer() const

@ -0,0 +1,520 @@
// 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 <OpenGl_FrameStats.hxx>
#include <OpenGl_GlCore20.hxx>
#include <OpenGl_View.hxx>
#include <OpenGl_Workspace.hxx>
IMPLEMENT_STANDARD_RTTIEXT(OpenGl_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;
}
if (thePostfix != NULL)
{
theStream << thePostfix;
}
return theStream;
}
//! Return estimated data size.
static Standard_Size estimatedDataSize (const Handle(OpenGl_Resource)& theRes)
{
return !theRes.IsNull() ? theRes->EstimatedDataSize() : 0;
}
}
// =======================================================================
// function : OpenGl_FrameStats
// 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));
}
// =======================================================================
// function : ~OpenGl_FrameStats
// purpose :
// =======================================================================
OpenGl_FrameStats::~OpenGl_FrameStats()
{
//
}
// =======================================================================
// function : FormatStats
// purpose :
// =======================================================================
TCollection_AsciiString OpenGl_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
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) << myFps
<< " [CPU: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 10) << std::fixed << std::setprecision (1) << myFpsCpu << "]\n";
}
else
{
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";
}
}
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());
}
// =======================================================================
// function : FrameStart
// purpose :
// =======================================================================
void OpenGl_FrameStats::FrameStart (const Handle(OpenGl_Workspace)& )
{
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)
{
return;
}
if (aTime > gp::Resolution())
{
// update FPS
myFpsTimer.Stop();
myFps = double(myFpsFrameCount) / aTime;
///const double aCpuSec = myFpsTimer.UserTimeCPU();
///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 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;
const Standard_Boolean toCountElems = (aBits & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0 || toCountTris || toCountMem;
const Standard_Boolean toCountGroups = (aBits & Graphic3d_RenderingParams::PerfCounters_Groups) != 0 || toCountElems;
const Standard_Boolean toCountStructs = (aBits & Graphic3d_RenderingParams::PerfCounters_Structures) != 0 || toCountGroups;
if (toCountStructs)
{
myCountersTmp[Counter_NbLayers] = theWorkspace->View()->LayerList().Layers().Size();
for (OpenGl_SequenceOfLayers::Iterator aLayerIter (theWorkspace->View()->LayerList().Layers()); aLayerIter.More(); aLayerIter.Next())
{
const Handle(OpenGl_Layer)& aLayer = aLayerIter.Value();
if (!aLayer->IsCulled())
{
++myCountersTmp[Counter_NbLayersNotCulled];
}
myCountersTmp[Counter_NbStructs] += aLayer->NbStructures();
myCountersTmp[Counter_NbStructsNotCulled] += aLayer->NbStructuresNotCulled();
if (toCountGroups)
{
updateStructures (aLayer->CullableStructuresBVH().Structures(), toCountStructs, toCountTris, toCountMem);
updateStructures (aLayer->CullableTrsfPersStructuresBVH().Structures(), toCountStructs, toCountTris, toCountMem);
updateStructures (aLayer->NonCullableStructures(), toCountStructs, toCountTris, toCountMem);
}
}
}
if (toCountMem
&& !theWorkspace.IsNull())
{
for (OpenGl_Context::OpenGl_ResourcesMap::Iterator aResIter (theWorkspace->GetGlContext()->SharedResources());
aResIter.More(); aResIter.Next())
{
myCountersTmp[Counter_EstimatedBytesTextures] += aResIter.Value()->EstimatedDataSize();
}
const OpenGl_View* aView = theWorkspace->View();
{
Standard_Size& aMemFbos = myCountersTmp[Counter_EstimatedBytesFbos];
// main FBOs
aMemFbos += estimatedDataSize (aView->myMainSceneFbos[0]);
aMemFbos += estimatedDataSize (aView->myMainSceneFbos[1]);
aMemFbos += estimatedDataSize (aView->myImmediateSceneFbos[0]);
aMemFbos += estimatedDataSize (aView->myImmediateSceneFbos[1]);
// OIT FBOs
aMemFbos += estimatedDataSize (aView->myMainSceneFbosOit[0]);
aMemFbos += estimatedDataSize (aView->myMainSceneFbosOit[1]);
aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[0]);
aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[1]);
// dump FBO
aMemFbos += estimatedDataSize (aView->myFBO);
// RayTracing FBO
aMemFbos += estimatedDataSize (aView->myOpenGlFBO);
aMemFbos += estimatedDataSize (aView->myOpenGlFBO2);
aMemFbos += estimatedDataSize (aView->myRaytraceFBO1[0]);
aMemFbos += estimatedDataSize (aView->myRaytraceFBO1[1]);
aMemFbos += estimatedDataSize (aView->myRaytraceFBO2[0]);
aMemFbos += estimatedDataSize (aView->myRaytraceFBO2[1]);
// also RayTracing
aMemFbos += estimatedDataSize (aView->myRaytraceOutputTexture[0]);
aMemFbos += estimatedDataSize (aView->myRaytraceOutputTexture[1]);
aMemFbos += estimatedDataSize (aView->myRaytraceVisualErrorTexture[0]);
aMemFbos += estimatedDataSize (aView->myRaytraceVisualErrorTexture[1]);
aMemFbos += estimatedDataSize (aView->myRaytraceTileOffsetsTexture[0]);
aMemFbos += estimatedDataSize (aView->myRaytraceTileOffsetsTexture[1]);
}
{
// Ray Tracing geometry
Standard_Size& aMemGeom = myCountersTmp[Counter_EstimatedBytesGeom];
aMemGeom += estimatedDataSize (aView->mySceneNodeInfoTexture);
aMemGeom += estimatedDataSize (aView->mySceneMinPointTexture);
aMemGeom += estimatedDataSize (aView->mySceneMaxPointTexture);
aMemGeom += estimatedDataSize (aView->mySceneTransformTexture);
aMemGeom += estimatedDataSize (aView->myGeometryVertexTexture);
aMemGeom += estimatedDataSize (aView->myGeometryNormalTexture);
aMemGeom += estimatedDataSize (aView->myGeometryTexCrdTexture);
aMemGeom += estimatedDataSize (aView->myGeometryTriangTexture);
aMemGeom += estimatedDataSize (aView->myRaytraceMaterialTexture);
aMemGeom += estimatedDataSize (aView->myRaytraceLightSrcTexture);
}
}
memcpy (myCounters, myCountersTmp, sizeof(myCounters));
}
// =======================================================================
// function : updateStructures
// purpose :
// =======================================================================
void OpenGl_FrameStats::updateStructures (const OpenGl_IndexedMapOfStructure& theStructures,
Standard_Boolean theToCountElems,
Standard_Boolean theToCountTris,
Standard_Boolean theToCountMem)
{
for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (theStructures); aStructIter.More(); aStructIter.Next())
{
const OpenGl_Structure* aStruct = aStructIter.Value();
if (aStruct->IsCulled())
{
if (theToCountMem)
{
for (OpenGl_Structure::GroupIterator aGroupIter (aStruct->Groups()); aGroupIter.More(); aGroupIter.Next())
{
const OpenGl_Group* aGroup = aGroupIter.Value();
for (const OpenGl_ElementNode* aNodeIter = aGroup->FirstNode(); aNodeIter != NULL; aNodeIter = aNodeIter->next)
{
if (const OpenGl_PrimitiveArray* aPrim = dynamic_cast<const OpenGl_PrimitiveArray*> (aNodeIter->elem))
{
myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
}
}
}
}
continue;
}
myCountersTmp[Counter_NbGroupsNotCulled] += aStruct->Groups().Size();
if (!theToCountElems)
{
continue;
}
for (OpenGl_Structure::GroupIterator aGroupIter (aStruct->Groups()); aGroupIter.More(); aGroupIter.Next())
{
const OpenGl_Group* aGroup = aGroupIter.Value();
for (const OpenGl_ElementNode* aNodeIter = aGroup->FirstNode(); aNodeIter != NULL; aNodeIter = aNodeIter->next)
{
if (const OpenGl_PrimitiveArray* aPrim = dynamic_cast<const OpenGl_PrimitiveArray*> (aNodeIter->elem))
{
++myCountersTmp[Counter_NbElemsNotCulled];
if (theToCountMem)
{
myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
}
/**if (aPrim->IsFillDrawMode())
{
++myCountersTmp[Counter_NbElemsFillNotCulled];
if (!theToCountTris)
{
continue;
}
const Handle(OpenGl_VertexBuffer)& anAttribs = aPrim->AttributesVbo();
if (anAttribs.IsNull()
|| !anAttribs->IsValid())
{
continue;
}
const Handle(OpenGl_VertexBuffer)& anIndices = aPrim->IndexVbo();
const Standard_Integer aNbIndices = !anIndices.IsNull() ? anIndices->GetElemsNb() : anAttribs->GetElemsNb();
const Standard_Integer aNbBounds = !aPrim->Bounds().IsNull() ? aPrim->Bounds()->NbBounds : 1;
switch (aPrim->DrawMode())
{
case GL_TRIANGLES:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 3;
break;
}
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices - 2 * aNbBounds;
break;
}
case GL_TRIANGLES_ADJACENCY:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 6;
break;
}
case GL_TRIANGLE_STRIP_ADJACENCY:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices - 4 * aNbBounds;
break;
}
#if !defined(GL_ES_VERSION_2_0)
case GL_QUADS:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 2;
break;
}
case GL_QUAD_STRIP:
{
myCountersTmp[Counter_NbTrianglesNotCulled] += (aNbIndices / 2 - aNbBounds) * 2;
break;
}
#endif
}
}
else if (aPrim->DrawMode() == GL_POINTS)
{
++myCountersTmp[Counter_NbElemsPointNotCulled];
if (theToCountTris)
{
const Handle(OpenGl_VertexBuffer)& anAttribs = aPrim->AttributesVbo();
if (!anAttribs.IsNull()
&& anAttribs->IsValid())
{
const Handle(OpenGl_VertexBuffer)& anIndices = aPrim->IndexVbo();
const Standard_Integer aNbIndices = !anIndices.IsNull() ? anIndices->GetElemsNb() : anAttribs->GetElemsNb();
myCountersTmp[Counter_NbPointsNotCulled] += aNbIndices;
}
}
}
else*/
{
++myCountersTmp[Counter_NbElemsLineNotCulled];
}
}
else if (const OpenGl_Text* aText = dynamic_cast<const OpenGl_Text*> (aNodeIter->elem))
{
(void )aText;
++myCountersTmp[Counter_NbElemsNotCulled];
++myCountersTmp[Counter_NbElemsTextNotCulled];
}
}
}
}
}

@ -0,0 +1,161 @@
// 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 _OpenGl_FrameStats_HeaderFile
#define _OpenGl_FrameStats_HeaderFile
#include <Graphic3d_RenderingParams.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
{
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 };
public:
//! Default constructor.
Standard_EXPORT OpenGl_FrameStats();
//! 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]; }
protected:
//! Updates counters for structures.
Standard_EXPORT virtual void updateStructures (const OpenGl_IndexedMapOfStructure& theStructures,
Standard_Boolean theToCountElems,
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)
#endif // _OpenGl_FrameStats_HeaderFile

@ -0,0 +1,144 @@
// 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 <OpenGl_FrameStatsPrs.hxx>
#include <OpenGl_View.hxx>
#include <OpenGl_ShaderManager.hxx>
#include <OpenGl_Workspace.hxx>
// =======================================================================
// function : OpenGl_FrameStatsPrs
// purpose :
// =======================================================================
OpenGl_FrameStatsPrs::OpenGl_FrameStatsPrs()
: myStatsPrev (new OpenGl_FrameStats())
{
myParams.HAlign = Graphic3d_HTA_CENTER;
myParams.VAlign = Graphic3d_VTA_CENTER;
myHasPlane = false;
}
// =======================================================================
// function : ~OpenGl_FrameStatsPrs
// purpose :
// =======================================================================
OpenGl_FrameStatsPrs::~OpenGl_FrameStatsPrs()
{
//
}
// =======================================================================
// function : Release
// purpose :
// =======================================================================
void OpenGl_FrameStatsPrs::Release (OpenGl_Context* theCtx)
{
OpenGl_Text::Release (theCtx);
}
// =======================================================================
// function : Update
// purpose :
// =======================================================================
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;
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)
{
myParams.HAlign = Graphic3d_HTA_LEFT;
}
else if (!myTrsfPers.IsNull() && (myTrsfPers->Corner2d() & Aspect_TOTP_RIGHT) != 0)
{
myParams.HAlign = Graphic3d_HTA_RIGHT;
}
if (!myTrsfPers.IsNull() && (myTrsfPers->Corner2d() & Aspect_TOTP_TOP) != 0)
{
myParams.VAlign = Graphic3d_VTA_TOP;
}
else if (!myTrsfPers.IsNull() && (myTrsfPers->Corner2d() & Aspect_TOTP_BOTTOM) != 0)
{
myParams.VAlign = Graphic3d_VTA_BOTTOM;
}
if (myParams.Height != aParamsPrev.Height
|| myParams.HAlign != aParamsPrev.HAlign
|| myParams.VAlign != aParamsPrev.VAlign)
{
Release (aCtx.operator->());
}
if (myStatsPrev->IsEqual (aStats)
&& !myString.IsEmpty())
{
return;
}
myStatsPrev->CopyFrom (aStats);
const TCollection_AsciiString aText = aStats->FormatStats (aRendParams.CollectedStats);
releaseVbos (aCtx.operator->());
myString.FromUnicode (aText.ToCString());
}
// =======================================================================
// function : Render
// purpose :
// =======================================================================
void OpenGl_FrameStatsPrs::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
{
const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
const Standard_Boolean wasEnabledDepth = theWorkspace->UseDepthWrite();
if (theWorkspace->UseDepthWrite())
{
theWorkspace->UseDepthWrite() = Standard_False;
glDepthMask (GL_FALSE);
}
aCtx->ModelWorldState.Push();
aCtx->ModelWorldState.ChangeCurrent().InitIdentity();
aCtx->WorldViewState.Push();
OpenGl_Mat4& aWorldView = aCtx->WorldViewState.ChangeCurrent();
if (!myTrsfPers.IsNull())
{
myTrsfPers->Apply (theWorkspace->View()->Camera(),
aCtx->ProjectionState.Current(), aWorldView,
aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);
}
aCtx->ApplyModelViewMatrix();
const OpenGl_AspectText* aTextAspectBack = theWorkspace->SetAspectText (&myTextAspect);
OpenGl_Text::Render (theWorkspace);
theWorkspace->SetAspectText (aTextAspectBack);
aCtx->WorldViewState.Pop();
aCtx->ModelWorldState.Pop();
aCtx->ApplyWorldViewMatrix();
if (theWorkspace->UseDepthWrite() != wasEnabledDepth)
{
theWorkspace->UseDepthWrite() = wasEnabledDepth;
glDepthMask (wasEnabledDepth ? GL_TRUE : GL_FALSE);
}
}

@ -0,0 +1,53 @@
// 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 _OpenGl_FrameStatsPrs_HeaderFile
#define _OpenGl_FrameStatsPrs_HeaderFile
#include <OpenGl_FrameStats.hxx>
#include <OpenGl_Text.hxx>
class Graphic3d_TransformPers;
//! Element rendering frame statistics.
class OpenGl_FrameStatsPrs : public OpenGl_Text
{
public:
//! Default constructor.
Standard_EXPORT OpenGl_FrameStatsPrs();
//! Destructor
Standard_EXPORT virtual ~OpenGl_FrameStatsPrs();
//! Render element.
Standard_EXPORT virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const Standard_OVERRIDE;
//! Release OpenGL resources.
Standard_EXPORT virtual void Release (OpenGl_Context* theCtx) Standard_OVERRIDE;
//! Update text.
Standard_EXPORT void Update (const Handle(OpenGl_Workspace)& theWorkspace);
//! Assign text aspect.
void SetTextAspect (const Handle(Graphic3d_AspectText3d)& theAspect) { myTextAspect.SetAspect (theAspect); }
protected:
OpenGl_AspectText myTextAspect; //!< text aspect
Handle(Graphic3d_TransformPers) myTrsfPers; //!< transformation persistence
Handle(OpenGl_FrameStats) myStatsPrev; //!< currently displayed stats
};
#endif // _OpenGl_FrameStatsPrs_HeaderFile

@ -32,10 +32,10 @@ OpenGl_Layer::OpenGl_Layer (const Standard_Integer theNbPriorities,
const Handle(Select3D_BVHBuilder3d)& theBuilder)
: myArray (0, theNbPriorities - 1),
myNbStructures (0),
myNbStructuresNotCulled (0),
myBVHPrimitivesTrsfPers (theBuilder),
myBVHIsLeftChildQueuedFirst (Standard_True),
myIsBVHPrimitivesNeedsReset (Standard_False),
myIsCulled (Standard_False)
myIsBVHPrimitivesNeedsReset (Standard_False)
{
myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
}
@ -488,15 +488,16 @@ void OpenGl_Layer::UpdateCulling (const OpenGl_BVHTreeSelector& theSelector,
{
updateBVH();
myIsCulled = false;
for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
{
const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
myNbStructuresNotCulled = myNbStructures;
for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitives.Structures()); aStructIter.More(); aStructIter.Next())
{
const OpenGl_Structure* aStruct = aStructIter.Value();
aStruct->SetCulled (theToTraverse);
}
for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitivesTrsfPers.Structures()); aStructIter.More(); aStructIter.Next())
{
const OpenGl_Structure* aStruct = aStructIter.Value();
aStruct->SetCulled (theToTraverse);
}
if (!theToTraverse)
@ -509,7 +510,7 @@ void OpenGl_Layer::UpdateCulling (const OpenGl_BVHTreeSelector& theSelector,
return;
}
myIsCulled = myAlwaysRenderedMap.IsEmpty();
myNbStructuresNotCulled = myAlwaysRenderedMap.Extent();
OpenGl_BVHTreeSelector::CullingContext aCullCtx;
theSelector.SetCullingDistance(aCullCtx, myLayerSettings.CullingDistance());
theSelector.SetCullingSize (aCullCtx, myLayerSettings.CullingSize());
@ -543,7 +544,6 @@ void OpenGl_Layer::UpdateCulling (const OpenGl_BVHTreeSelector& theSelector,
continue;
}
myIsCulled = false;
Standard_Integer aStack[BVH_Constants_MaxTreeDepth];
Standard_Integer aHead = -1;
Standard_Integer aNode = 0; // a root node
@ -584,6 +584,7 @@ void OpenGl_Layer::UpdateCulling (const OpenGl_BVHTreeSelector& theSelector,
? myBVHPrimitivesTrsfPers.GetStructureById (aIdx)
: myBVHPrimitives.GetStructureById (aIdx);
aStruct->MarkAsNotCulled();
++myNbStructuresNotCulled;
if (aHead < 0)
{
break;

@ -80,6 +80,9 @@ public:
//! @return the number of structures
Standard_Integer NbStructures() const { return myNbStructures; }
//! Number of NOT culled structures in the layer.
Standard_Integer NbStructuresNotCulled() const { return myNbStructuresNotCulled; }
//! Returns the number of available priority levels
Standard_Integer NbPriorities() const { return myArray.Length(); }
@ -125,7 +128,7 @@ public:
const Standard_Boolean theToTraverse);
//! Returns TRUE if layer is empty or has been discarded entirely by culling test.
bool IsCulled() const { return myNbStructures == 0 || myIsCulled; }
bool IsCulled() const { return myNbStructuresNotCulled == 0; }
// Render all structures.
void Render (const Handle(OpenGl_Workspace)& theWorkspace,
@ -137,13 +140,24 @@ public:
return myBVHPrimitivesTrsfPers.Size();
}
public:
//! Returns set of OpenGl_Structures structures for building BVH tree.
const OpenGl_BVHClipPrimitiveSet& CullableStructuresBVH() const { return myBVHPrimitives; }
//! Returns set of transform persistent OpenGl_Structures for building BVH tree.
const OpenGl_BVHClipPrimitiveTrsfPersSet& CullableTrsfPersStructuresBVH() const { return myBVHPrimitivesTrsfPers; }
//! Returns indexed map of always rendered structures.
const NCollection_IndexedMap<const OpenGl_Structure*>& NonCullableStructures() const { return myAlwaysRenderedMap; }
protected:
//! Updates BVH trees if their state has been invalidated.
void updateBVH() const;
Standard_EXPORT void updateBVH() const;
//! Iterates through the hierarchical list of existing structures and renders them all.
void renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const;
Standard_EXPORT void renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const;
private:
@ -153,6 +167,9 @@ private:
//! Overall number of structures rendered in the layer.
Standard_Integer myNbStructures;
//! Number of NOT culled structures in the layer.
Standard_Integer myNbStructuresNotCulled;
//! Layer setting flags.
Graphic3d_ZLayerSettings myLayerSettings;
@ -174,9 +191,6 @@ private:
//! Defines if the cached bounding box is outdated.
mutable bool myIsBoundingBoxNeedsReset[2];
//! Flag indicating that this layer is marked culled as whole
bool myIsCulled;
//! Cached layer bounding box.
mutable Bnd_Box myBoundingBox[2];

@ -56,6 +56,9 @@ public:
//! Release GL resources.
virtual void Release (OpenGl_Context* theGlCtx) Standard_OVERRIDE;
//! Returns estimated GPU memory usage - not implemented.
virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE { return 0; }
//! Index of currently selected type of hatch.
int TypeOfHatch() const { return myTypeOfHatch; }

@ -224,7 +224,8 @@ Standard_Boolean OpenGl_PrimitiveArray::initNormalVbo (const Handle(OpenGl_Conte
case 10: myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 10>(*myAttribs); break;
}
if (!myVboAttribs->init (theCtx, 0, myAttribs->NbElements, myAttribs->Data(), GL_NONE, myAttribs->Stride))
// specify data type as Byte and NbComponents as Stride, so that OpenGl_VertexBuffer::EstimatedDataSize() will return correct value
if (!myVboAttribs->init (theCtx, myAttribs->Stride, myAttribs->NbElements, myAttribs->Data(), GL_UNSIGNED_BYTE, myAttribs->Stride))
{
TCollection_ExtendedString aMsg;
aMsg += "VBO creation for Primitive Array has failed for ";

@ -97,6 +97,14 @@ public:
const Handle(Graphic3d_Buffer)& theAttribs,
const Handle(Graphic3d_BoundBuffer)& theBounds);
public:
//! Returns index VBO.
const Handle(OpenGl_VertexBuffer)& IndexVbo() const { return myVboIndices; }
//! Returns attributes VBO.
const Handle(OpenGl_VertexBuffer)& AttributesVbo() const { return myVboAttribs; }
protected:
//! VBO initialization procedures

@ -45,6 +45,9 @@ public:
//! @param theGlCtx - bound GL context, shouldn't be NULL.
Standard_EXPORT virtual void Release (OpenGl_Context* theGlCtx) = 0;
//! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules.
virtual Standard_Size EstimatedDataSize() const = 0;
private:
//! Copy should be performed only within Handles!

@ -44,6 +44,9 @@ public:
//! Destroys object - will release GPU memory if any.
Standard_EXPORT virtual void Release (OpenGl_Context* theContext) Standard_OVERRIDE;
//! Returns estimated GPU memory usage - not implemented.
virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE { return 0; }
//! Creates an uninitialized sampler object.
Standard_EXPORT Standard_Boolean Create (const Handle(OpenGl_Context)& theContext);

@ -55,6 +55,9 @@ public:
//! Destroys shader object.
Standard_EXPORT virtual void Release (OpenGl_Context* theCtx) Standard_OVERRIDE;
//! Returns estimated GPU memory usage - not implemented.
virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE { return 0; }
//! Returns type of shader object.
GLenum Type() const { return myType; }

@ -176,6 +176,9 @@ public:
//! Destroys shader program.
Standard_EXPORT virtual void Release (OpenGl_Context* theCtx) Standard_OVERRIDE;
//! Returns estimated GPU memory usage - cannot be easily estimated.
virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE { return 0; }
//! Attaches shader object to the program object.
Standard_EXPORT Standard_Boolean AttachShader (const Handle(OpenGl_Context)& theCtx,
const Handle(OpenGl_ShaderObject)& theShader);

@ -119,11 +119,8 @@ public:
//! Releases structure resources.
virtual void Release (const Handle(OpenGl_Context)& theGlCtx);
//! Marks structure as culled/not culled.
void SetCulled (Standard_Boolean theIsCulled) const
{
myIsCulled = theIsCulled && !IsAlwaysRendered();
}
//! Marks structure as culled/not culled - note that IsAlwaysRendered() is ignored here!
void SetCulled (Standard_Boolean theIsCulled) const { myIsCulled = theIsCulled; }
//! Marks structure as overlapping the current view volume one.
//! The method is called during traverse of BVH tree.

@ -114,10 +114,10 @@ protected:
friend class OpenGl_Trihedron;
friend class OpenGl_GraduatedTrihedron;
private:
//! Release cached VBO resources
void releaseVbos (OpenGl_Context* theCtx);
Standard_EXPORT void releaseVbos (OpenGl_Context* theCtx);
private:
//! Setup matrix.
void setupMatrix (const Handle(OpenGl_Context)& theCtx,

@ -60,6 +60,8 @@ OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId,
mySizeY (0),
mySizeZ (0),
myTextFormat (GL_RGBA),
mySizedFormat(GL_RGBA8),
myNbSamples (1),
myHasMipmaps (Standard_False),
myIsAlpha (false)
{
@ -433,6 +435,8 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
myHasMipmaps = toCreateMipMaps;
myTextFormat = thePixelFormat;
mySizedFormat = theTextFormat;
myNbSamples = 1;
#if !defined(GL_ES_VERSION_2_0)
const GLint anIntFormat = theTextFormat;
#else
@ -546,6 +550,7 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
theSizeX, 0,
thePixelFormat, theDataType, NULL);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
if (aTestWidth == 0)
{
// no memory or broken input parameters
@ -597,6 +602,7 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
thePixelFormat, theDataType, NULL);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
if (aTestWidth == 0 || aTestHeight == 0)
{
// no memory or broken input parameters
@ -660,6 +666,7 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
thePixelFormat, theDataType, NULL);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
if (aTestWidth == 0 || aTestHeight == 0)
{
// no memory or broken input parameters
@ -768,8 +775,9 @@ bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
return false;
}
const GLsizei aNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
myTarget = GL_TEXTURE_2D_MULTISAMPLE;
myHasMipmaps = false;
if(theSizeX > theCtx->MaxTextureSize()
|| theSizeY > theCtx->MaxTextureSize())
{
@ -778,17 +786,18 @@ bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
Bind (theCtx);
//myTextFormat = theTextFormat;
mySizedFormat = theTextFormat;
#if !defined(GL_ES_VERSION_2_0)
if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
{
theCtx->Functions()->glTexStorage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
}
else
{
theCtx->Functions()->glTexImage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
theCtx->Functions()->glTexImage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
}
#else
theCtx->Functions() ->glTexStorage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
theCtx->Functions() ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
#endif
if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
{
@ -819,6 +828,8 @@ bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
#if !defined(GL_ES_VERSION_2_0)
myTarget = GL_TEXTURE_RECTANGLE;
myNbSamples = 1;
myHasMipmaps = false;
const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
@ -826,26 +837,19 @@ bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
Bind (theCtx);
applyDefaultSamplerParams (theCtx);
const GLint anIntFormat = theFormat.Internal();
myTextFormat = theFormat.Format();
mySizedFormat = theFormat.Internal();
glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE,
0,
anIntFormat,
aSizeX,
aSizeY,
0,
theFormat.Format(),
GL_FLOAT,
NULL);
glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
aSizeX, aSizeY, 0,
myTextFormat, GL_FLOAT, NULL);
GLint aTestSizeX = 0;
GLint aTestSizeY = 0;
glGetTexLevelParameteriv (
GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
glGetTexLevelParameteriv (
GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
if (aTestSizeX == 0 || aTestSizeY == 0)
{
@ -853,15 +857,9 @@ bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
return false;
}
glTexImage2D (myTarget,
0,
anIntFormat,
aSizeX,
aSizeY,
0,
theFormat.Format(),
GL_FLOAT,
NULL);
glTexImage2D (myTarget, 0, mySizedFormat,
aSizeX, aSizeY, 0,
myTextFormat, GL_FLOAT, NULL);
if (glGetError() != GL_NO_ERROR)
{
@ -914,6 +912,8 @@ bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
}
myTarget = GL_TEXTURE_3D;
myNbSamples = 1;
myHasMipmaps = false;
const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
@ -936,19 +936,12 @@ bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
return false;
}
const GLint anIntFormat = theTextFormat;
mySizedFormat = theTextFormat;
#if !defined (GL_ES_VERSION_2_0)
theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D,
0,
anIntFormat,
aSizeX,
aSizeY,
aSizeZ,
0,
thePixelFormat,
theDataType,
NULL);
theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
aSizeX, aSizeY, aSizeZ, 0,
thePixelFormat, theDataType, NULL);
GLint aTestSizeX = 0;
GLint aTestSizeY = 0;
@ -957,6 +950,7 @@ bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeZ);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
if (aTestSizeX == 0 || aTestSizeY == 0 || aTestSizeZ == 0)
{
@ -967,16 +961,9 @@ bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
#endif
applyDefaultSamplerParams (theCtx);
theCtx->Functions()->glTexImage3D (myTarget,
0,
anIntFormat,
aSizeX,
aSizeY,
aSizeZ,
0,
thePixelFormat,
theDataType,
thePixels);
theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat,
aSizeX, aSizeY, aSizeZ, 0,
thePixelFormat, theDataType, thePixels);
if (glGetError() != GL_NO_ERROR)
{
@ -992,3 +979,76 @@ bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
Unbind (theCtx);
return true;
}
// =======================================================================
// function : PixelSizeOfPixelFormat
// purpose :
// =======================================================================
Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theInternalFormat)
{
switch(theInternalFormat)
{
// RED variations (GL_RED, OpenGL 3.0+)
case GL_RED:
case GL_R8: return 1;
case GL_R16: return 2;
case GL_R16F: return 2;
case GL_R32F: return 4;
// RGB variations
case GL_RGB: return 3;
case GL_RGB8: return 3;
case GL_RGB16: return 6;
case GL_RGB16F: return 6;
case GL_RGB32F: return 12;
// RGBA variations
case GL_RGBA: return 4;
case GL_RGBA8: return 4;
case GL_RGB10_A2: return 4;
case GL_RGBA12: return 6;
case GL_RGBA16: return 8;
case GL_RGBA16F: return 8;
case GL_RGBA32F: return 16;
//
case GL_BGRA_EXT: return 4;
// ALPHA variations (deprecated)
case GL_ALPHA:
case GL_ALPHA8: return 1;
case GL_ALPHA16: return 2;
case GL_LUMINANCE: return 1;
case GL_LUMINANCE_ALPHA: return 2;
// depth-stencil
case GL_DEPTH24_STENCIL8: return 4;
case GL_DEPTH32F_STENCIL8: return 8;
case GL_DEPTH_COMPONENT16: return 2;
case GL_DEPTH_COMPONENT24: return 3;
case GL_DEPTH_COMPONENT32F: return 4;
}
return 0;
}
// =======================================================================
// function : EstimatedDataSize
// purpose :
// =======================================================================
Standard_Size OpenGl_Texture::EstimatedDataSize() const
{
if (!IsValid())
{
return 0;
}
Standard_Size aSize = PixelSizeOfPixelFormat (mySizedFormat) * mySizeX * myNbSamples;
if (mySizeY != 0)
{
aSize *= Standard_Size(mySizeY);
}
if (mySizeZ != 0)
{
aSize *= Standard_Size(mySizeZ);
}
if (myHasMipmaps)
{
aSize = aSize + aSize / 3;
}
return aSize;
}

@ -289,6 +289,11 @@ public:
//! Helpful constants
static const GLuint NO_TEXTURE = 0;
//! Return pixel size of pixel format in bytes.
//! Note that this method considers that OpenGL natively supports this pixel format,
//! which might be not the case - in the latter case, actual pixel size might differ!
Standard_EXPORT static Standard_Size PixelSizeOfPixelFormat (Standard_Integer theInternalFormat);
public:
//! Create uninitialized texture.
@ -445,6 +450,9 @@ public:
GLenum& thePixelFormat,
GLenum& theDataType);
//! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules.
Standard_EXPORT virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE;
protected:
//! Apply default sampler parameters after texture creation.
@ -460,6 +468,8 @@ protected:
GLsizei mySizeY; //!< texture height
GLsizei mySizeZ; //!< texture depth
GLenum myTextFormat; //!< texture format - GL_RGB, GL_RGBA,...
GLint mySizedFormat;//!< internal (sized) texture format
Standard_Integer myNbSamples; //!< number of MSAA samples
Standard_Boolean myHasMipmaps; //!< flag indicates that texture was uploaded with mipmaps
bool myIsAlpha; //!< indicates alpha format

@ -225,6 +225,14 @@ public:
public: //! @name advanced methods
//! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules.
virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE
{
return IsValid()
? sizeOfGlType (myDataType) * myComponentsNb * myElemsNb
: 0;
}
//! @return size of specified GL type
static size_t sizeOfGlType (const GLenum theType)
{

@ -142,6 +142,7 @@ OpenGl_View::~OpenGl_View()
void OpenGl_View::ReleaseGlResources (const Handle(OpenGl_Context)& theCtx)
{
myGraduatedTrihedron.Release (theCtx.operator->());
myFrameStatsPrs.Release (theCtx.operator->());
if (!myTextureEnv.IsNull())
{

@ -40,6 +40,7 @@
#include <OpenGl_BVHTreeSelector.hxx>
#include <OpenGl_Context.hxx>
#include <OpenGl_FrameBuffer.hxx>
#include <OpenGl_FrameStatsPrs.hxx>
#include <OpenGl_GraduatedTrihedron.hxx>
#include <OpenGl_LayerList.hxx>
#include <OpenGl_Light.hxx>
@ -420,6 +421,9 @@ protected: //! @name Rendering of GL graphics (with prepared drawing buffer).
//! Renders trihedron.
void renderTrihedron (const Handle(OpenGl_Workspace) &theWorkspace);
//! Renders frame statistics.
void renderFrameStats();
private:
//! Adds the structure to display lists of the view.
@ -502,6 +506,7 @@ protected:
OpenGl_BVHTreeSelector myBVHSelector;
OpenGl_GraduatedTrihedron myGraduatedTrihedron;
OpenGl_FrameStatsPrs myFrameStatsPrs;
Handle(OpenGl_TextureSet) myTextureEnv;
@ -1090,6 +1095,7 @@ public:
friend class OpenGl_GraphicDriver;
friend class OpenGl_Workspace;
friend class OpenGl_LayerList;
friend class OpenGl_FrameStats;
};
#endif // _OpenGl_View_Header

@ -29,6 +29,7 @@
#include <OpenGl_AspectLine.hxx>
#include <OpenGl_Context.hxx>
#include <OpenGl_FrameStats.hxx>
#include <OpenGl_Matrix.hxx>
#include <OpenGl_Workspace.hxx>
#include <OpenGl_View.hxx>
@ -163,6 +164,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);
// release pending GL resources
aCtx->ReleaseDelayed();
@ -559,6 +561,7 @@ void OpenGl_View::Redraw()
// reset render mode state
aCtx->FetchState();
aCtx->FrameStats()->FrameEnd (myWorkspace);
myWasRedrawnGL = Standard_True;
}
@ -584,6 +587,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);
if ( aFrameBuffer == NULL
&& !aCtx->DefaultFrameBuffer().IsNull()
@ -721,6 +725,7 @@ void OpenGl_View::RedrawImmediate()
{
aCtx->core11fwd->glFlush();
}
aCtx->FrameStats()->FrameEnd (myWorkspace);
myWasRedrawnGL = Standard_True;
}
@ -1004,6 +1009,10 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
glDisable (GL_CULL_FACE);
}
}
else
{
renderFrameStats();
}
// reset FFP state for safety
aContext->BindProgram (Handle(OpenGl_ShaderProgram)());
@ -1136,6 +1145,20 @@ void OpenGl_View::renderTrihedron (const Handle(OpenGl_Workspace) &theWorkspace)
}
}
//=======================================================================
//function : renderFrameStats
//purpose :
//=======================================================================
void OpenGl_View::renderFrameStats()
{
if (myRenderParams.ToShowStats
&& myRenderParams.CollectedStats != Graphic3d_RenderingParams::PerfCounters_NONE)
{
myFrameStatsPrs.Update (myWorkspace);
myFrameStatsPrs.Render (myWorkspace);
}
}
// =======================================================================
// function : Invalidate
// purpose :

@ -9731,6 +9731,113 @@ static int VLight (Draw_Interpretor& theDi,
return 0;
}
//! Read Graphic3d_RenderingParams::PerfCounters flag.
static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theValue,
Standard_Boolean& theToReset,
Graphic3d_RenderingParams::PerfCounters& theFlagsRem,
Graphic3d_RenderingParams::PerfCounters& theFlagsAdd)
{
Graphic3d_RenderingParams::PerfCounters aFlag = Graphic3d_RenderingParams::PerfCounters_NONE;
TCollection_AsciiString aVal = theValue;
Standard_Boolean toReverse = Standard_False;
if (aVal == "none")
{
theToReset = Standard_True;
return Standard_True;
}
else if (aVal.StartsWith ("-"))
{
toReverse = Standard_True;
aVal = aVal.SubString (2, aVal.Length());
}
else if (aVal.StartsWith ("no"))
{
toReverse = Standard_True;
aVal = aVal.SubString (3, aVal.Length());
}
else if (aVal.StartsWith ("+"))
{
aVal = aVal.SubString (2, aVal.Length());
}
else
{
theToReset = Standard_True;
}
if ( aVal == "fps"
|| aVal == "framerate") aFlag = Graphic3d_RenderingParams::PerfCounters_FrameRate;
else if (aVal == "cpu") aFlag = Graphic3d_RenderingParams::PerfCounters_CPU;
else if (aVal == "layers") aFlag = Graphic3d_RenderingParams::PerfCounters_Layers;
else if (aVal == "structs"
|| aVal == "structures"
|| aVal == "objects") aFlag = Graphic3d_RenderingParams::PerfCounters_Structures;
else if (aVal == "groups") aFlag = Graphic3d_RenderingParams::PerfCounters_Groups;
else if (aVal == "arrays") aFlag = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
else if (aVal == "tris"
|| aVal == "triangles") aFlag = Graphic3d_RenderingParams::PerfCounters_Triangles;
else if (aVal == "pnts"
|| aVal == "points") aFlag = Graphic3d_RenderingParams::PerfCounters_Points;
else if (aVal == "mem"
|| aVal == "gpumem"
|| aVal == "estimmem") aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
else if (aVal == "basic") aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
else if (aVal == "extended"
|| aVal == "verbose"
|| aVal == "extra") aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
else
{
return Standard_False;
}
if (toReverse)
{
theFlagsRem = Graphic3d_RenderingParams::PerfCounters(theFlagsRem | aFlag);
}
else
{
theFlagsAdd = Graphic3d_RenderingParams::PerfCounters(theFlagsAdd | aFlag);
}
return Standard_True;
}
//! Read Graphic3d_RenderingParams::PerfCounters flags.
static Standard_Boolean convertToPerfStatsFlags (const TCollection_AsciiString& theValue,
Graphic3d_RenderingParams::PerfCounters& theFlags)
{
TCollection_AsciiString aValue = theValue;
Graphic3d_RenderingParams::PerfCounters aFlagsRem = Graphic3d_RenderingParams::PerfCounters_NONE;
Graphic3d_RenderingParams::PerfCounters aFlagsAdd = Graphic3d_RenderingParams::PerfCounters_NONE;
Standard_Boolean toReset = Standard_False;
for (;;)
{
Standard_Integer aSplitPos = aValue.Search ("|");
if (aSplitPos <= 0)
{
if (!parsePerfStatsFlag (aValue, toReset, aFlagsRem, aFlagsAdd))
{
return Standard_False;
}
if (toReset)
{
theFlags = Graphic3d_RenderingParams::PerfCounters_NONE;
}
theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags | aFlagsAdd);
theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags & ~aFlagsRem);
return Standard_True;
}
if (aSplitPos > 1)
{
TCollection_AsciiString aSubValue = aValue.SubString (1, aSplitPos - 1);
if (!parsePerfStatsFlag (aSubValue, toReset, aFlagsRem, aFlagsAdd))
{
return Standard_False;
}
}
aValue = aValue.SubString (aSplitPos + 1, aValue.Length());
}
}
//=======================================================================
//function : VRenderParams
//purpose : Enables/disables rendering features
@ -9827,6 +9934,46 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
case V3d_GOURAUD: theDI << "gouraud"; break;
case V3d_PHONG: theDI << "phong"; break;
}
{
theDI << "perfCounters:";
if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
{
theDI << " fps";
}
if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
{
theDI << " cpu";
}
if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
{
theDI << " structs";
}
if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
{
theDI << " groups";
}
if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
{
theDI << " arrays";
}
if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
{
theDI << " tris";
}
if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
{
theDI << " pnts";
}
if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
{
theDI << " gpumem";
}
if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
{
theDI << " none";
}
theDI << "\n";
}
theDI << "depth pre-pass: " << (aParams.ToEnableDepthPrepass ? "on" : "off") << "\n";
theDI << "\n";
return 0;
@ -10451,6 +10598,39 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
return 1;
}
}
else if (aFlag == "-performancestats"
|| aFlag == "-performancecounters"
|| aFlag == "-perfstats"
|| aFlag == "-perfcounters"
|| aFlag == "-stats")
{
if (++anArgIter >= theArgNb)
{
std::cout << "Error: wrong syntax at argument '" << anArg << "'\n";
return 1;
}
TCollection_AsciiString aFlagsStr (theArgVec[anArgIter]);
aFlagsStr.LowerCase();
Graphic3d_RenderingParams::PerfCounters aFlags = aView->ChangeRenderingParams().CollectedStats;
if (!convertToPerfStatsFlags (aFlagsStr, aFlags))
{
std::cout << "Error: wrong syntax at argument '" << anArg << "'\n";
return 1;
}
aView->ChangeRenderingParams().CollectedStats = aFlags;
aView->ChangeRenderingParams().ToShowStats = aFlags != Graphic3d_RenderingParams::PerfCounters_NONE;
}
else if (aFlag == "-perfupdateinterval"
|| aFlag == "-statsupdateinterval")
{
if (++anArgIter >= theArgNb)
{
std::cout << "Error: wrong syntax at argument '" << anArg << "'\n";
return 1;
}
aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
}
else
{
std::cout << "Error: wrong syntax, unknown flag '" << anArg << "'\n";
@ -11970,6 +12150,9 @@ 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 Show/hide performance counters (flags can be combined)"
"\n '-perfUpdateInterval nbSeconds' Performance counters update interval"
"\n Unlike vcaps, these parameters dramatically change visual properties."
"\n Command is intended to control presentation quality depending on"
"\n hardware capabilities and performance.",

@ -15,18 +15,15 @@ set SMALL_WIN_HEIGHT 512
# other
array set aSphereNames {}
set aWithoutClippingSnapshot $imagedir/${casename}_without.png
set aWithClippingSnapshot $imagedir/${casename}_with.png
set aDiffImage $imagedir/${casename}_diff.png
pload VISUALIZATION MODELING
vclear
vinit name=small_wnd l=32 t=32 w=$SMALL_WIN_WIDTH h=$SMALL_WIN_HEIGHT
vactivate small_wnd
vrenderparams -perfUpdateInterval 0
vfrustumculling 0
vautozfit 0
vviewparams -scale 1.953125 -eye 0.57735026918962573 -0.57735026918962573 0.57735026918962573
vzrange 1 512
vclear
vremove -all -noinfo
puts [vdrawsphere tmp_sph $SPHERE_FINENESS]
@ -60,7 +57,10 @@ for {set i $aInnerSpheresNum} {$i < $SPHERES_NUM} {incr i} {
set aSphereNames($i) $aCurrName
}
puts [vfps]
vdump $aWithoutClippingSnapshot
vrenderparams -perfCounters none
vdump $imagedir/${casename}_cull_off_ref.png
vrenderparams -perfCounters verbose|nofps|nocpu
vdump $imagedir/${casename}_cull_off.png
puts "All spheres were displayed."
puts ""
@ -70,13 +70,14 @@ puts "Start displaying spheres with clipping..."
vfrustumculling 1
vdisplayall
puts [vfps]
vdump $aWithClippingSnapshot
vrenderparams -perfCounters none
vdump $imagedir/${casename}_cull_on_ref.png
vrenderparams -perfCounters verbose|nofps|nocpu
vdump $imagedir/${casename}_cull_on.png
puts "All spheres were displayed."
puts ""
set aDiffImageResult [diffimage $aWithClippingSnapshot $aWithoutClippingSnapshot 0.1 0 0 $aDiffImage]
set aDiffImageResult [diffimage $imagedir/${casename}_cull_on_ref.png $imagedir/${casename}_cull_off_ref.png 0.1 0 0 $imagedir/${casename}_diff.png]
if {$aDiffImageResult != 0} {
puts "ERROR : Test failed: there is a difference between images rendered with and without clipping"
}
verase

@ -14,18 +14,15 @@ set SMALL_WIN_HEIGHT 512
# other
array set aBoxNames {}
set aWithoutClippingSnapshot $imagedir/${casename}_without.png
set aWithClippingSnapshot $imagedir/${casename}_with.png
set aDiffImage $imagedir/${casename}_diff.png
pload VISUALIZATION MODELING
vclear
vinit name=small_wnd l=32 t=32 w=$SMALL_WIN_WIDTH h=$SMALL_WIN_HEIGHT
vactivate small_wnd
vrenderparams -perfUpdateInterval 0
vfrustumculling 0
vautozfit 0
vviewparams -scale 1.953125 -eye 0.57735026918962573 -0.57735026918962573 0.57735026918962573
vzrange 1 512
vclear
vremove -all -noinfo
set aInnerBoxesNum [expr $BOXES_NUM * $PERCENT_OF_INNER_BOXES / 100]
@ -63,7 +60,10 @@ for {set i 0} {$i < $BOXES_NUM} {incr i} {
vdisplay -noupdate $aBoxNames($i)
}
puts [vfps]
vdump $aWithoutClippingSnapshot
vrenderparams -perfCounters none
vdump $imagedir/${casename}_cull_off_ref.png
vrenderparams -perfCounters verbose|nofps|nocpu
vdump $imagedir/${casename}_cull_off.png
puts "All boxes were displayed."
puts ""
@ -75,12 +75,13 @@ for {set i 0} {$i < $BOXES_NUM} {incr i} {
vdisplay -noupdate $aBoxNames($i)
}
puts [vfps]
vdump $aWithClippingSnapshot
vrenderparams -perfCounters none
vdump $imagedir/${casename}_cull_on_ref.png
vrenderparams -perfCounters verbose|nofps|nocpu
vdump $imagedir/${casename}_cull_on.png
puts "All boxes were displayed."
set aDiffImageResult [diffimage $aWithClippingSnapshot $aWithoutClippingSnapshot 0.1 0 0 $aDiffImage]
set aDiffImageResult [diffimage $imagedir/${casename}_cull_on_ref.png $imagedir/${casename}_cull_off_ref.png 0.1 0 0 $imagedir/${casename}_diff.png]
if {$aDiffImageResult != 0} {
puts "ERROR : Test failed: there is a difference between images rendered with and without clipping"
}
verase