0023081: This is desirable to retrieve GPU memory information from graphic driver
authorkgv <kgv@opencascade.com>
Thu, 12 Apr 2012 08:49:54 +0000 (12:49 +0400)
committerkgv <kgv@opencascade.com>
Thu, 12 Apr 2012 08:49:54 +0000 (12:49 +0400)
Added Graphic3d_GraphicDriver::MemoryInfo() function.
Added vfps command to estimate average frame rate of 3D Viewer
Simplified vdrawsphere command
Removed turnVbo and performance measurements from vdrawsphere.
Added vvbo command to control VBO usage flag.
Added vmemgpu command to display GPU memory info from graphic driver

src/Draw/Draw_BasicCommands.cxx
src/Graphic3d/Graphic3d_GraphicDriver.cdl
src/OSD/FILES
src/OSD/OSD.cdl
src/OSD/OSD_MemInfo.cxx [new file with mode: 0644]
src/OSD/OSD_MemInfo.hxx [new file with mode: 0644]
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_GraphicDriver.cxx
src/OpenGl/OpenGl_GraphicDriver.hxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx

index e4731cf..ab56205 100755 (executable)
@@ -29,6 +29,7 @@
 
 #include <Message.hxx>
 #include <Message_Messenger.hxx>
+#include <OSD_MemInfo.hxx>
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
@@ -419,6 +420,58 @@ By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
   return 0;
 }
 
+//==============================================================================
+//function : dmeminfo
+//purpose  :
+//==============================================================================
+
+static int dmeminfo (Draw_Interpretor& theDI,
+                     Standard_Integer  theArgNb,
+                     const char**      theArgVec)
+{
+  OSD_MemInfo aMemInfo;
+  if (theArgNb <= 1)
+  {
+    theDI << aMemInfo.ToString();
+    return 0;
+  }
+
+  for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anIter]);
+    anArg.LowerCase();
+    if (anArg == "virt" || anArg == "v")
+    {
+      theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemVirtual)) << " ";
+    }
+    else if (anArg == "wset" || anArg == "w")
+    {
+      theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSet)) << " ";
+    }
+    else if (anArg == "wsetpeak")
+    {
+      theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSetPeak)) << " ";
+    }
+    else if (anArg == "swap")
+    {
+      theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsage)) << " ";
+    }
+    else if (anArg == "swappeak")
+    {
+      theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsagePeak)) << " ";
+    }
+    else if (anArg == "private")
+    {
+      theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemPrivate)) << " ";
+    }
+    else
+    {
+      std::cerr << "Unknown argument '" << theArgVec[anIter] << "'!\n";
+    }
+  }
+  theDI << "\n";
+  return 0;
+}
 
 void Draw::BasicCommands(Draw_Interpretor& theCommands)
 {
@@ -443,4 +496,8 @@ void Draw::BasicCommands(Draw_Interpretor& theCommands)
   theCommands.Add("mallochook",
                   "debug memory allocation/deallocation, w/o args for help",
                   __FILE__, mallochook, g);
+  theCommands.Add ("meminfo",
+    "meminfo [virt|v] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
+    " : memory counters for this process",
+         __FILE__, dmeminfo, g);
 }
index eaac147..7d5cf4a 100755 (executable)
@@ -62,6 +62,7 @@ uses
     Array1OfReal        from TColStd,
     Array2OfReal        from TColStd,
 
+    AsciiString         from TCollection,
     ExtendedString      from TCollection,
 
     NameOfColor         from Quantity,
@@ -625,6 +626,11 @@ is
                is deferred;
     ---Purpose: enables/disables usage of OpenGL vertex buffer arrays while drawing primitiev arrays
 
+    MemoryInfo (me;
+                theFreeBytes : out Size from Standard;
+                theInfo      : out AsciiString from TCollection) returns Boolean from Standard is deferred;
+    ---Purpose: Returns information about GPU memory usage.
+
     ----------------------------------------
     ---Category: Methods to create Triedron
     -- for Purpose : see Graphic3d_Group.cdl
index a1c5a34..510ba51 100755 (executable)
@@ -23,3 +23,5 @@ OSD_PerfMeter.h
 OSD_PerfMeter.hxx
 OSD_MAllocHook.cxx
 OSD_MAllocHook.hxx
+OSD_MemInfo.hxx
+OSD_MemInfo.cxx
index b6adf8f..930d527 100755 (executable)
@@ -174,6 +174,7 @@ is
              ---Purpose: Provides tools to load a shared library
              --          and retrieve the address of an entry point.
 
+     imported MemInfo;
      imported PThread;
      imported ThreadFunction;
          class Thread;
diff --git a/src/OSD/OSD_MemInfo.cxx b/src/OSD/OSD_MemInfo.cxx
new file mode 100644 (file)
index 0000000..b493bbd
--- /dev/null
@@ -0,0 +1,207 @@
+// Created on: 2011-10-05
+// Created by: Kirill GAVRILOV
+// Copyright (c) 2012 OPEN CASCADE SAS
+//
+// The content of this file is subject to the Open CASCADE Technology Public
+// License Version 6.5 (the "License"). You may not use the content of this file
+// except in compliance with the License. Please obtain a copy of the License
+// at http://www.opencascade.org and read it completely before using this file.
+//
+// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
+// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+//
+// The Original Code and all software distributed under the License is
+// distributed on an "AS IS" basis, without warranty of any kind, and the
+// Initial Developer hereby disclaims all such warranties, including without
+// limitation, any warranties of merchantability, fitness for a particular
+// purpose or non-infringement. Please see the License for the specific terms
+// and conditions governing the rights and limitations under the License.
+
+#if (defined(_WIN32) || defined(__WIN32__))
+  #include <windows.h>
+  #include <winbase.h>
+  #include <process.h>
+  #include <Psapi.h>
+  #ifdef _MSC_VER
+    #pragma comment(lib, "Psapi.lib")
+  #endif
+#elif (defined(__APPLE__))
+  #include <mach/task.h>
+  #include <mach/mach.h>
+#endif
+
+#include <string>
+#include <sstream>
+#include <fstream>
+
+#include <OSD_MemInfo.hxx>
+
+// =======================================================================
+// function : OSD_MemInfo
+// purpose  :
+// =======================================================================
+OSD_MemInfo::OSD_MemInfo()
+{
+  Update();
+}
+
+// =======================================================================
+// function : Update
+// purpose  :
+// =======================================================================
+void OSD_MemInfo::Update()
+{
+  // reset values
+  for (Standard_Integer anIter = 0; anIter < MemCounter_NB; ++anIter)
+  {
+    myCounters[anIter] = Standard_Size(-1);
+  }
+
+#if (defined(_WIN32) || defined(__WIN32__))
+  MEMORYSTATUSEX aStatEx;
+  aStatEx.dwLength = sizeof(aStatEx);
+  GlobalMemoryStatusEx (&aStatEx);
+  myCounters[MemVirtual] = Standard_Size(aStatEx.ullTotalVirtual - aStatEx.ullAvailVirtual);
+
+  // use Psapi library
+  HANDLE aProcess = GetCurrentProcess();
+  PROCESS_MEMORY_COUNTERS_EX aProcMemCnts;
+  if (GetProcessMemoryInfo (aProcess, (PROCESS_MEMORY_COUNTERS* )&aProcMemCnts, sizeof(aProcMemCnts)))
+  {
+    myCounters[MemPrivate]        = aProcMemCnts.PrivateUsage;
+    myCounters[MemWorkingSet]     = aProcMemCnts.WorkingSetSize;
+    myCounters[MemWorkingSetPeak] = aProcMemCnts.PeakWorkingSetSize;
+    myCounters[MemSwapUsage]      = aProcMemCnts.PagefileUsage;
+    myCounters[MemSwapUsagePeak]  = aProcMemCnts.PeakPagefileUsage;
+  }
+#elif (defined(__linux__) || defined(__linux))
+  // use procfs on Linux
+  char aBuff[4096];
+  snprintf (aBuff, sizeof(aBuff), "/proc/%d/status", getpid());
+  std::ifstream aFile;
+  aFile.open (aBuff);
+  if (!aFile.is_open())
+  {
+    return;
+  }
+
+  while (!aFile.eof())
+  {
+    memset (aBuff, 0, sizeof(aBuff));
+    aFile.getline (aBuff, 4096);
+    if (aBuff[0] == '\0')
+    {
+      continue;
+    }
+
+    if (strncmp (aBuff, "VmSize:", strlen ("VmSize:")) == 0)
+    {
+      myCounters[MemVirtual] = atol (aBuff + strlen ("VmSize:")) * 1024;
+    }
+    //else if (strncmp (aBuff, "VmPeak:", strlen ("VmPeak:")) == 0)
+    //  myVirtualPeak = atol (aBuff + strlen ("VmPeak:")) * 1024;
+    else if (strncmp (aBuff, "VmRSS:", strlen ("VmRSS:")) == 0)
+    {
+      myCounters[MemWorkingSet] = atol (aBuff + strlen ("VmRSS:")) * 1024; // RSS - resident set size
+    }
+    else if (strncmp (aBuff, "VmHWM:", strlen ("VmHWM:")) == 0)
+    {
+      myCounters[MemWorkingSetPeak] = atol (aBuff + strlen ("VmHWM:")) * 1024; // HWM - high water mark
+    }
+    else if (strncmp (aBuff, "VmData:", strlen ("VmData:")) == 0)
+    {
+      if (myCounters[MemPrivate] == Standard_Size(-1)) ++myCounters[MemPrivate];
+      myCounters[MemPrivate] += atol (aBuff + strlen ("VmData:")) * 1024;
+    }
+    else if (strncmp (aBuff, "VmStk:", strlen ("VmStk:")) == 0)
+    {
+      if (myCounters[MemPrivate] == Standard_Size(-1)) ++myCounters[MemPrivate];
+      myCounters[MemPrivate] += atol (aBuff + strlen ("VmStk:")) * 1024;
+    }
+  }
+  aFile.close();
+#elif (defined(__APPLE__))
+  struct task_basic_info aTaskInfo;
+  mach_msg_type_number_t aTaskInfoCount = TASK_BASIC_INFO_COUNT;
+  if (task_info (mach_task_self(), TASK_BASIC_INFO,
+                 (task_info_t )&aTaskInfo, &aTaskInfoCount) == KERN_SUCCESS)
+  {
+    // On Mac OS X, these values in bytes, not pages!
+    myCounters[MemVirtual]    = aTaskInfo.virtual_size;
+    myCounters[MemWorkingSet] = aTaskInfo.resident_size;
+  }
+#endif
+}
+
+// =======================================================================
+// function : ToString
+// purpose  :
+// =======================================================================
+TCollection_AsciiString OSD_MemInfo::ToString() const
+{
+  TCollection_AsciiString anInfo;
+  if (myCounters[MemPrivate] != Standard_Size(-1))
+  {
+    anInfo += TCollection_AsciiString("  Private memory:     ") + Standard_Integer (ValueMiB (MemPrivate)) + " MiB\n";
+  }
+  if (myCounters[MemWorkingSet] != Standard_Size(-1))
+  {
+    anInfo += TCollection_AsciiString("  Working Set:        ") +  Standard_Integer (ValueMiB (MemWorkingSet)) + " MiB";
+    if (myCounters[MemWorkingSetPeak] != Standard_Size(-1))
+    {
+      anInfo += TCollection_AsciiString(" (peak: ") +  Standard_Integer (ValueMiB (MemWorkingSetPeak)) + " MiB)";
+    }
+    anInfo += "\n";
+  }
+  if (myCounters[MemSwapUsage] != Standard_Size(-1))
+  {
+    anInfo += TCollection_AsciiString("  Pagefile usage:     ") +  Standard_Integer (ValueMiB (MemSwapUsage)) + " MiB";
+    if (myCounters[MemSwapUsagePeak] != Standard_Size(-1))
+    {
+      anInfo += TCollection_AsciiString(" (peak: ") +  Standard_Integer (ValueMiB (MemSwapUsagePeak)) + " MiB)";
+    }
+    anInfo += "\n";
+  }
+  if (myCounters[MemVirtual] != Standard_Size(-1))
+  {
+    anInfo += TCollection_AsciiString("  Virtual memory:     ") +  Standard_Integer (ValueMiB (MemVirtual)) + " MiB\n";
+  }
+  return anInfo;
+}
+
+// =======================================================================
+// function : Value
+// purpose  :
+// =======================================================================
+Standard_Size OSD_MemInfo::Value (const OSD_MemInfo::Counter theCounter) const
+{
+  if (theCounter < 0 || theCounter >= MemCounter_NB)
+  {
+    return Standard_Size(-1);
+  }
+  return myCounters[theCounter];
+}
+
+// =======================================================================
+// function : ValueMiB
+// purpose  :
+// =======================================================================
+Standard_Size OSD_MemInfo::ValueMiB (const OSD_MemInfo::Counter theCounter) const
+{
+  if (theCounter < 0 || theCounter >= MemCounter_NB)
+  {
+    return Standard_Size(-1);
+  }
+  return (myCounters[theCounter] == Standard_Size(-1))
+       ? Standard_Size(-1) : (myCounters[theCounter] / (1024 * 1024));
+}
+
+// =======================================================================
+// function : ShowInfo
+// purpose  :
+// =======================================================================
+TCollection_AsciiString OSD_MemInfo::PrintInfo()
+{
+  OSD_MemInfo anInfo;
+  return anInfo.ToString();
+}
diff --git a/src/OSD/OSD_MemInfo.hxx b/src/OSD/OSD_MemInfo.hxx
new file mode 100644 (file)
index 0000000..5e2e3c8
--- /dev/null
@@ -0,0 +1,102 @@
+// Created on: 2011-10-05
+// Created by: Kirill GAVRILOV
+// Copyright (c) 2012 OPEN CASCADE SAS
+//
+// The content of this file is subject to the Open CASCADE Technology Public
+// License Version 6.5 (the "License"). You may not use the content of this file
+// except in compliance with the License. Please obtain a copy of the License
+// at http://www.opencascade.org and read it completely before using this file.
+//
+// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
+// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+//
+// The Original Code and all software distributed under the License is
+// distributed on an "AS IS" basis, without warranty of any kind, and the
+// Initial Developer hereby disclaims all such warranties, including without
+// limitation, any warranties of merchantability, fitness for a particular
+// purpose or non-infringement. Please see the License for the specific terms
+// and conditions governing the rights and limitations under the License.
+
+#ifndef _OSD_MemInfo_H__
+#define _OSD_MemInfo_H__
+
+#include <Standard_Transient.hxx>
+#include <TCollection_AsciiString.hxx>
+
+//! This class provide information about memory utilized by current process.
+//! This information includes:
+//!  - Private Memory - synthetic value that tries to filter out the memory
+//!                     usage only by the process itself (allocated for data
+//!                     and stack), excluding dynamic libraries.
+//!                     These pages may be in RAM or in SWAP.
+//!  - Virtual Memory - amount of reserved and committed memory in the
+//!                     user-mode portion of the virtual address space.
+//!                     Notice that this counter includes reserved memory
+//!                     (not yet in used) and shared between processes memory (libraries).
+//!  - Working Set    - set of memory pages in the virtual address space of the process
+//!                     that are currently resident in physical memory (RAM).
+//!                     These pages are available for an application to use
+//!                     without triggering a page fault.
+//!  - Pagefile Usage - space allocated for the pagefile, in bytes.
+//!                     Those pages may or may not be in memory (RAM)
+//!                     thus this counter couldn't be used to estimate
+//!                     how many active pages doesn't present in RAM.
+//!
+//! Notice that none of these counters can be used as absolute measure of
+//! application memory consumption!
+//!
+//! User should analyze all values in specific case to make correct decision
+//! about memory (over)usage. This is also prefferred to use specialized
+//! tools to detect memory leaks.
+//!
+//! This also means that these values should not be used for intellectual
+//! memory management by application itself.
+class OSD_MemInfo : public Standard_Transient
+{
+
+public:
+
+  enum Counter
+  {
+    MemPrivate = 0,    //!< Virtual memory allocated for data and stack excluding libraries
+    MemVirtual,        //!< Reserved and committed memory of the virtual address space
+    MemWorkingSet,     //!< Memory pages that are currently resident in physical memory
+    MemWorkingSetPeak, //!< Peak working set size
+    MemSwapUsage,      //!< Space allocated for the pagefile
+    MemSwapUsagePeak,  //!< Peak space allocated for the pagefile
+    MemCounter_NB      //!< Indicates total counters number
+  };
+
+public:
+
+  //! Create and initialize
+  Standard_EXPORT OSD_MemInfo();
+
+  //! Update counters
+  Standard_EXPORT void Update();
+
+  //! Return the string representation for all available counter.
+  Standard_EXPORT TCollection_AsciiString ToString() const;
+
+  //! Return value or specified counter in bytes.
+  //! Notice that NOT all counters are available on various systems.
+  //! Standard_Size(-1) means invalid (unavailable) value.
+  Standard_EXPORT Standard_Size Value (const OSD_MemInfo::Counter theCounter) const;
+
+  //! Return value or specified counter in MiB.
+  //! Notice that NOT all counters are available on various systems.
+  //! Standard_Size(-1) means invalid (unavailable) value.
+  Standard_EXPORT Standard_Size ValueMiB (const OSD_MemInfo::Counter theCounter) const;
+
+public:
+
+  //! Return the string representation for all available counter.
+  Standard_EXPORT static TCollection_AsciiString PrintInfo();
+
+private:
+
+  Standard_Size myCounters[MemCounter_NB]; //!< Counters' values, in bytes
+
+};
+
+#endif // _OSD_MemInfo_H__
index 0c29b09..eb99984 100644 (file)
   #include <GL/glx.h> // glXGetProcAddress()
 #endif
 
+// GL_NVX_gpu_memory_info
+#ifndef GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX
+  enum
+  {
+    GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX         = 0x9047,
+    GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX   = 0x9048,
+    GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX = 0x9049,
+    GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX           = 0x904A,
+    GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX           = 0x904B
+  };
+#endif
+
 IMPLEMENT_STANDARD_HANDLE (OpenGl_Context, Standard_Transient)
 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Context, Standard_Transient)
 
@@ -56,6 +68,8 @@ OpenGl_Context::OpenGl_Context()
   core20 (NULL),
   arbVBO (NULL),
   extFBO (NULL),
+  atiMem (Standard_False),
+  nvxMem (Standard_False),
   myGlLibHandle (NULL),
   myGlCore20 (NULL),
   myGlVerMajor (0),
@@ -189,11 +203,11 @@ Standard_Boolean OpenGl_Context::CheckExtension (const char* theExtName) const
 // function : Init
 // purpose  :
 // =======================================================================
-void OpenGl_Context::Init()
+Standard_Boolean OpenGl_Context::Init()
 {
   if (myIsInitialized)
   {
-    return;
+    return Standard_True;
   }
 
 #if (defined(_WIN32) || defined(__WIN32__))
@@ -204,9 +218,14 @@ void OpenGl_Context::Init()
   myGContext = (Aspect_RenderingContext )glXGetCurrentContext();
   myWindow   = (Aspect_Drawable )glXGetCurrentDrawable();
 #endif
+  if (myGContext == NULL)
+  {
+    return Standard_False;
+  }
 
   init();
   myIsInitialized = Standard_True;
+  return Standard_True;
 }
 
 // =======================================================================
@@ -214,13 +233,13 @@ void OpenGl_Context::Init()
 // purpose  :
 // =======================================================================
 #if (defined(_WIN32) || defined(__WIN32__))
-void OpenGl_Context::Init (const Aspect_Handle           theWindow,
-                           const Aspect_Handle           theWindowDC,
-                           const Aspect_RenderingContext theGContext)
+Standard_Boolean OpenGl_Context::Init (const Aspect_Handle           theWindow,
+                                       const Aspect_Handle           theWindowDC,
+                                       const Aspect_RenderingContext theGContext)
 #else
-void OpenGl_Context::Init (const Aspect_Drawable         theWindow,
-                           const Aspect_Display          theDisplay,
-                           const Aspect_RenderingContext theGContext)
+Standard_Boolean OpenGl_Context::Init (const Aspect_Drawable         theWindow,
+                                       const Aspect_Display          theDisplay,
+                                       const Aspect_RenderingContext theGContext)
 #endif
 {
   Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called only once!");
@@ -232,9 +251,14 @@ void OpenGl_Context::Init (const Aspect_Drawable         theWindow,
 #else
   myDisplay  = theDisplay;
 #endif
+  if (myGContext == NULL)
+  {
+    return Standard_False;
+  }
 
   init();
   myIsInitialized = Standard_True;
+  return Standard_True;
 }
 
 // =======================================================================
@@ -332,6 +356,9 @@ void OpenGl_Context::init()
   // read version
   readGlVersion();
 
+  atiMem = CheckExtension ("GL_ATI_meminfo");
+  nvxMem = CheckExtension ("GL_NVX_gpu_memory_info");
+
   // initialize VBO extension (ARB)
   if (CheckExtension ("GL_ARB_vertex_buffer_object"))
   {
@@ -607,7 +634,6 @@ void OpenGl_Context::init()
     core20 = myGlCore20;
   }
 }
-
 // =======================================================================
 // function : IsFeedback
 // purpose  :
@@ -625,3 +651,77 @@ void OpenGl_Context::SetFeedback (const Standard_Boolean theFeedbackOn)
 {
   myIsFeedback = theFeedbackOn;
 }
+
+// =======================================================================
+// function : MemoryInfo
+// purpose  :
+// =======================================================================
+Standard_Size OpenGl_Context::AvailableMemory() const
+{
+  if (atiMem)
+  {
+    // this is actually information for VBO pool
+    // however because pools are mostly shared
+    // it can be used for total GPU memory estimations
+    GLint aMemInfo[4];
+    aMemInfo[0] = 0;
+    glGetIntegerv (GL_VBO_FREE_MEMORY_ATI, aMemInfo);
+    // returned value is in KiB, however this maybe changed in future
+    return Standard_Size(aMemInfo[0]) * 1024;
+  }
+  else if (nvxMem)
+  {
+    // current available dedicated video memory (in KiB), currently unused GPU memory
+    GLint aMemInfo = 0;
+    glGetIntegerv (GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &aMemInfo);
+    return Standard_Size(aMemInfo) * 1024;
+  }
+  return 0;
+}
+
+// =======================================================================
+// function : MemoryInfo
+// purpose  :
+// =======================================================================
+TCollection_AsciiString OpenGl_Context::MemoryInfo() const
+{
+  TCollection_AsciiString anInfo;
+  if (atiMem)
+  {
+    GLint aValues[4];
+    memset (aValues, 0, sizeof(aValues));
+    glGetIntegerv (GL_VBO_FREE_MEMORY_ATI, aValues);
+
+    // total memory free in the pool
+    anInfo += TCollection_AsciiString ("  GPU free memory:    ") + (aValues[0] / 1024) + " MiB\n";
+
+    // largest available free block in the pool
+    anInfo += TCollection_AsciiString ("  Largest free block: ") + (aValues[1] / 1024) + " MiB\n";
+    if (aValues[2] != aValues[0])
+    {
+      // total auxiliary memory free
+      anInfo += TCollection_AsciiString ("  Free memory:        ") + (aValues[2] / 1024) + " MiB\n";
+    }
+  }
+  else if (nvxMem)
+  {
+    //current available dedicated video memory (in KiB), currently unused GPU memory
+    GLint aValue = 0;
+    glGetIntegerv (GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &aValue);
+    anInfo += TCollection_AsciiString ("  GPU free memory:    ") + (aValue / 1024) + " MiB\n";
+
+    // dedicated video memory, total size (in KiB) of the GPU memory
+    GLint aDedicated = 0;
+    glGetIntegerv (GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &aDedicated);
+    anInfo += TCollection_AsciiString ("  GPU memory:         ") + (aDedicated / 1024) + " MiB\n";
+
+    // total available memory, total size (in KiB) of the memory available for allocations
+    glGetIntegerv (GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &aValue);
+    if (aValue != aDedicated)
+    {
+      // different only for special configurations
+      anInfo += TCollection_AsciiString ("  Total memory:       ") + (aValue / 1024) + " MiB\n";
+    }
+  }
+  return anInfo;
+}
index 96f4ad0..9fa6dd8 100644 (file)
@@ -26,6 +26,7 @@
 #include <Aspect_Display.hxx>
 #include <Aspect_RenderingContext.hxx>
 #include <Standard_Transient.hxx>
+#include <TCollection_AsciiString.hxx>
 #include <Handle_OpenGl_Context.hxx>
 
 //! Forward declarations
@@ -82,16 +83,16 @@ public:
 
   //! Initialize available extensions.
   //! GL context should be active!
-  Standard_EXPORT void Init();
+  Standard_EXPORT Standard_Boolean Init();
 
 #if (defined(_WIN32) || defined(__WIN32__))
-  Standard_EXPORT void Init (const Aspect_Handle           theWindow,
-                             const Aspect_Handle           theWindowDC,
-                             const Aspect_RenderingContext theGContext);
+  Standard_EXPORT Standard_Boolean Init (const Aspect_Handle           theWindow,
+                                         const Aspect_Handle           theWindowDC,
+                                         const Aspect_RenderingContext theGContext);
 #else
-  Standard_EXPORT void Init (const Aspect_Drawable         theWindow,
-                             const Aspect_Display          theDisplay,
-                             const Aspect_RenderingContext theGContext);
+  Standard_EXPORT Standard_Boolean Init (const Aspect_Drawable         theWindow,
+                                         const Aspect_Display          theDisplay,
+                                         const Aspect_RenderingContext theGContext);
 #endif
 
   //! Check if theExtName extension is supported by active GL context.
@@ -130,6 +131,18 @@ public:
   //! Setup feedback mode cached state
   Standard_EXPORT void SetFeedback (const Standard_Boolean theFeedbackOn);
 
+  //! This function retrieves information from GL about free GPU memory that is:
+  //!  - OS-dependent. On some OS it is per-process and on others - for entire system.
+  //!  - Vendor-dependent. Currently available only on NVIDIA and AMD/ATi drivers only.
+  //!  - Numbers meaning may vary.
+  //! You should use this info only for diagnostics purposes.
+  //! @return free GPU dedicated memory in bytes.
+  Standard_EXPORT Standard_Size AvailableMemory() const;
+
+  //! This function retrieves information from GL about GPU memory
+  //! and contains more vendor-specific values than AvailableMemory().
+  Standard_EXPORT TCollection_AsciiString MemoryInfo() const;
+
 private:
 
   //! Wrapper to system function to retrieve GL function pointer by name.
@@ -151,8 +164,10 @@ public: // core profiles
 
 public: // extensions
 
-  OpenGl_ArbVBO*   arbVBO;
-  OpenGl_ExtFBO*   extFBO;
+  OpenGl_ArbVBO*   arbVBO; //!< GL_ARB_vertex_buffer_object
+  OpenGl_ExtFBO*   extFBO; //!< GL_EXT_framebuffer_object
+  Standard_Boolean atiMem; //!< GL_ATI_meminfo
+  Standard_Boolean nvxMem; //!< GL_NVX_gpu_memory_info
 
 private:
 
@@ -171,7 +186,7 @@ private:
   Standard_Integer myGlVerMajor;    //!< cached GL version major number
   Standard_Integer myGlVerMinor;    //!< cached GL version minor number
   Standard_Boolean myIsFeedback;    //!< flag indicates GL_FEEDBACK mode
-  Standard_Boolean myIsInitialized; //!< flag to indicate initialization state
+  Standard_Boolean myIsInitialized; //!< flag indicates initialization state
 
 public:
 
index 260adbe..0df9140 100755 (executable)
@@ -20,6 +20,7 @@
 
 #include <OpenGl_GraphicDriver.hxx>
 
+#include <OpenGl_Context.hxx>
 #include <OpenGl_View.hxx>
 #include <OpenGl_Workspace.hxx>
 
@@ -55,34 +56,56 @@ extern "C" {
 #endif
 }
 
+// =======================================================================
+// function : OpenGl_GraphicDriver
+// purpose  :
+// =======================================================================
 OpenGl_GraphicDriver::OpenGl_GraphicDriver (const Standard_CString theShrName)
 : Graphic3d_GraphicDriver (theShrName)
 {
   //
 }
 
+// =======================================================================
+// function : DefaultTextHeight
+// purpose  :
+// =======================================================================
 Standard_ShortReal OpenGl_GraphicDriver::DefaultTextHeight() const
 {
   return 16.;
 }
 
+// =======================================================================
+// function : GetMapOfViews
+// purpose  :
+// =======================================================================
 NCollection_DataMap<Standard_Integer, Handle(OpenGl_View)>& OpenGl_GraphicDriver::GetMapOfViews()
 {
   return TheMapOfView;
 }
 
+// =======================================================================
+// function : GetMapOfWorkspaces
+// purpose  :
+// =======================================================================
 NCollection_DataMap<Standard_Integer, Handle(OpenGl_Workspace)>& OpenGl_GraphicDriver::GetMapOfWorkspaces()
 {
   return TheMapOfWS;
 }
 
+// =======================================================================
+// function : GetMapOfStructures
+// purpose  :
+// =======================================================================
 NCollection_DataMap<Standard_Integer, OpenGl_Structure*>& OpenGl_GraphicDriver::GetMapOfStructures()
 {
   return TheMapOfStructure;
 }
 
-//TsmInitUpdateState
-// Deprecated, need to decide what to do with EraseAnimation() call
+// =======================================================================
+// function : InvalidateAllWorkspaces
+// purpose  : ex-TsmInitUpdateState, deprecated, need to decide what to do with EraseAnimation() call
+// =======================================================================
 void OpenGl_GraphicDriver::InvalidateAllWorkspaces()
 {
   for (NCollection_DataMap<Standard_Integer, Handle(OpenGl_Workspace)>::Iterator anIt (OpenGl_GraphicDriver::GetMapOfWorkspaces());
@@ -92,12 +115,38 @@ void OpenGl_GraphicDriver::InvalidateAllWorkspaces()
   }
 }
 
+// =======================================================================
+// function : ToUseVBO
+// purpose  :
+// =======================================================================
 Standard_Boolean OpenGl_GraphicDriver::ToUseVBO()
 {
   return TheToUseVbo;
 }
 
+// =======================================================================
+// function : EnableVBO
+// purpose  :
+// =======================================================================
 void OpenGl_GraphicDriver::EnableVBO (const Standard_Boolean theToTurnOn)
 {
   TheToUseVbo = theToTurnOn;
 }
+
+// =======================================================================
+// function : MemoryInfo
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_GraphicDriver::MemoryInfo (Standard_Size&           theFreeBytes,
+                                                   TCollection_AsciiString& theInfo) const
+{
+  // this is extra work (for OpenGl_Context initialization)...
+  OpenGl_Context aGlCtx;
+  if (!aGlCtx.Init())
+  {
+    return Standard_False;
+  }
+  theFreeBytes = aGlCtx.AvailableMemory();
+  theInfo      = aGlCtx.MemoryInfo();
+  return !theInfo.IsEmpty();
+}
index a852dba..4579958 100644 (file)
@@ -327,6 +327,11 @@ public:
   //! Warning! This method should be called only before any primitives are displayed in GL scene!
   Standard_EXPORT void EnableVBO (const Standard_Boolean theToTurnOn);
 
+  //! Returns information about GPU memory usage.
+  //! Please read OpenGl_Context::MemoryInfo() for more description.
+  Standard_EXPORT Standard_Boolean MemoryInfo (Standard_Size&           theFreeBytes,
+                                               TCollection_AsciiString& theInfo) const;
+
 private:
 
   //! Access the global map of views.
index 7a536c4..b5cd888 100755 (executable)
@@ -2772,6 +2772,51 @@ static int VVbo (Draw_Interpretor& theDI,
   return 0;
 }
 
+//==============================================================================
+//function : VMemGpu
+//purpose  :
+//==============================================================================
+
+static int VMemGpu (Draw_Interpretor& theDI,
+                    Standard_Integer  theArgNb,
+                    const char**      theArgVec)
+{
+  // get the context
+  Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
+  if (aContextAIS.IsNull())
+  {
+    std::cerr << "No active view. Please call vinit.\n";
+    return 1;
+  }
+
+  Handle(Graphic3d_GraphicDriver) aDriver =
+         Handle(Graphic3d_GraphicDriver)::DownCast (aContextAIS->CurrentViewer()->Device()->GraphicDriver());
+  if (aDriver.IsNull())
+  {
+    std::cerr << "Graphic driver not available.\n";
+    return 1;
+  }
+
+  Standard_Size aFreeBytes = 0;
+  TCollection_AsciiString anInfo;
+  if (!aDriver->MemoryInfo (aFreeBytes, anInfo))
+  {
+    std::cerr << "Information not available.\n";
+    return 1;
+  }
+
+  if (theArgNb > 1 && *theArgVec[1] == 'f')
+  {
+    theDI << Standard_Real (aFreeBytes);
+  }
+  else
+  {
+    theDI << anInfo;
+  }
+
+  return 0;
+}
+
 //=======================================================================
 //function : ViewerCommands
 //purpose  :
@@ -2879,4 +2924,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
   theCommands.Add ("vvbo",
     "vvbo {0|1} : turn VBO usage On/Off; affects only newly displayed objects",
     __FILE__, VVbo, group);
+  theCommands.Add ("vmemgpu",
+    "vmemgpu [f]: print system-dependent GPU memory information if available;"
+    " with f option returns free memory in bytes",
+    __FILE__, VMemGpu, group);
 }