From ddb9ed4810c4b409992d6e73107e4067ad7e0015 Mon Sep 17 00:00:00 2001
From: kgv <kgv@opencascade.com>
Date: Sat, 15 Jan 2022 01:39:19 +0300
Subject: [PATCH] 0032779: Visualization, TKOpenGl - support using a wide color
 window buffer format (10bit per component / 30bit RGB)

Added new flag OpenGl_Caps::buffersDeepColor disabled by default.
OpenGl_Window now tries to find a RGB10_A2 pixel format using wglChoosePixelFormatARB().
OpenGl_TextureFormat::FindSizedFormat() - added handling of GL_RGB10_A2 internal format.
OpenGl_View::SetWindow() now selects preferred FBO color format basing on parameters.
OpenGl_Context::DiagnosticInformation()/OpenGl_View::DiagnosticInformation() now include
information about window pixel format / FBO texture format.
---
 src/OpenGl/OpenGl_Caps.cxx             |   2 +
 src/OpenGl/OpenGl_Caps.hxx             |  19 +++
 src/OpenGl/OpenGl_Context.cxx          |  66 ++++++++++
 src/OpenGl/OpenGl_Context.hxx          |   8 ++
 src/OpenGl/OpenGl_DepthPeeling.cxx     |  10 +-
 src/OpenGl/OpenGl_FrameBuffer.cxx      |  19 ++-
 src/OpenGl/OpenGl_FrameBuffer.hxx      |  14 +-
 src/OpenGl/OpenGl_GraphicDriver.cxx    |  67 ++++++----
 src/OpenGl/OpenGl_ShadowMap.cxx        |   2 +-
 src/OpenGl/OpenGl_TextureFormat.cxx    |  10 ++
 src/OpenGl/OpenGl_View.cxx             |  62 ++++++---
 src/OpenGl/OpenGl_Window.cxx           |  15 ++-
 src/OpenGlTest/OpenGlTest_Commands.cxx | 175 ++++++++-----------------
 13 files changed, 281 insertions(+), 188 deletions(-)

diff --git a/src/OpenGl/OpenGl_Caps.cxx b/src/OpenGl/OpenGl_Caps.cxx
index cc72994b89..140a767d00 100755
--- a/src/OpenGl/OpenGl_Caps.cxx
+++ b/src/OpenGl/OpenGl_Caps.cxx
@@ -34,6 +34,7 @@ OpenGl_Caps::OpenGl_Caps()
   useZeroToOneDepth (Standard_False),
   buffersNoSwap     (Standard_False),
   buffersOpaqueAlpha(Standard_True),
+  buffersDeepColor  (Standard_False),
   contextStereo     (Standard_False),
   contextDebug      (Standard_False),
   contextSyncDebug  (Standard_False),
@@ -73,6 +74,7 @@ OpenGl_Caps& OpenGl_Caps::operator= (const OpenGl_Caps& theCopy)
   useZeroToOneDepth = theCopy.useZeroToOneDepth;
   buffersNoSwap     = theCopy.buffersNoSwap;
   buffersOpaqueAlpha= theCopy.buffersOpaqueAlpha;
+  buffersDeepColor  = theCopy.buffersDeepColor;
   contextStereo     = theCopy.contextStereo;
   contextDebug      = theCopy.contextDebug;
   contextSyncDebug  = theCopy.contextSyncDebug;
diff --git a/src/OpenGl/OpenGl_Caps.hxx b/src/OpenGl/OpenGl_Caps.hxx
index 67d0eba38f..5281e046da 100755
--- a/src/OpenGl/OpenGl_Caps.hxx
+++ b/src/OpenGl/OpenGl_Caps.hxx
@@ -60,6 +60,25 @@ public: //! @name context creation parameters
    */
   Standard_Boolean buffersOpaqueAlpha;
 
+  /**
+   * Specify whether deep color format (10-bit per component / 30-bit RGB) should be used
+   * instead of  standard color format  (8-bit per component / 24-bit RGB) when available.
+   * Deep color provides higher accuracy within the same color range (sRGB)
+   * and doesn't enable wide color gamut / HDR support.
+   * Higher precision helps eliminating banding effect on smooth gradients.
+   *
+   * Effect of the flag will vary depending on platform:
+   * - used as a hint on systems with 24-bit RGB color defined as preferred pixels format
+   *   but with 30-bit RGB color being activated systemwide (e.g. Windows);
+   * - ignored on systems with deep color defined as preferred pixel format (e.g. Linux / X11),
+   *   deep 30-bit RGB color will be used regardless of the flag value;
+   * - ignored on configurations not supporting deep color (incompatible display / system / GPU / driver),
+   *   standard 24-bit RGB color will be used instead.
+   *
+   * OFF by default.
+   */
+  Standard_Boolean buffersDeepColor;
+
   /**
    * Request stereoscopic context (with Quad Buffer). This flag requires support in OpenGL driver.
    *
diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx
index 4d2bac38b9..0f269886e9 100644
--- a/src/OpenGl/OpenGl_Context.cxx
+++ b/src/OpenGl/OpenGl_Context.cxx
@@ -243,7 +243,9 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myColorMask (true),
   myAlphaToCoverage (false),
   myIsGlDebugCtx (false),
+  myIsWindowDeepColor (false),
   myIsSRgbWindow (false),
+  myIsSRgbActive (false),
   myResolution (Graphic3d_RenderingParams::THE_DEFAULT_RESOLUTION),
   myResolutionRatio (1.0f),
   myLineWidthScale (1.0f),
@@ -1529,6 +1531,11 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     }
   }
 
+  Graphic3d_Vec4i aWinBitsRGBA;
+  Graphic3d_Vec2i aWinBitsDepthStencil;
+  WindowBufferBits (aWinBitsRGBA, aWinBitsDepthStencil);
+  myIsWindowDeepColor = aWinBitsRGBA.r() >= 10;
+
   // standard formats
   mySupportedFormats->Add (Image_Format_Gray);
   mySupportedFormats->Add (Image_Format_Alpha);
@@ -1813,6 +1820,58 @@ void OpenGl_Context::MemoryInfo (TColStd_IndexedDataMapOfStringString& theDict)
 #endif
 }
 
+// =======================================================================
+// function : WindowBufferBits
+// purpose  :
+// =======================================================================
+void OpenGl_Context::WindowBufferBits (Graphic3d_Vec4i& theColorBits,
+                                       Graphic3d_Vec2i& theDepthStencilBits) const
+{
+  if (core11ffp != NULL
+   || myGapi == Aspect_GraphicsLibrary_OpenGLES)
+  {
+    // removed from core with no working alternative
+    core11fwd->glGetIntegerv (GL_RED_BITS,     &theColorBits.r());
+    core11fwd->glGetIntegerv (GL_GREEN_BITS,   &theColorBits.g());
+    core11fwd->glGetIntegerv (GL_BLUE_BITS,    &theColorBits.b());
+    core11fwd->glGetIntegerv (GL_ALPHA_BITS,   &theColorBits.a());
+    core11fwd->glGetIntegerv (GL_DEPTH_BITS,   &theDepthStencilBits[0]);
+    core11fwd->glGetIntegerv (GL_STENCIL_BITS, &theDepthStencilBits[1]);
+  }
+  else
+  {
+  #if defined(HAVE_EGL)
+    //
+  #elif defined(_WIN32)
+    const int aPixFrmtIndex = GetPixelFormat ((HDC )myDisplay);
+    PIXELFORMATDESCRIPTOR aFormat;
+    memset (&aFormat, 0, sizeof(aFormat));
+    aFormat.nSize      = sizeof(aFormat);
+    DescribePixelFormat ((HDC )myDisplay, aPixFrmtIndex, sizeof(PIXELFORMATDESCRIPTOR), &aFormat);
+    theColorBits.SetValues (aFormat.cRedBits, aFormat.cGreenBits, aFormat.cBlueBits, aFormat.cAlphaBits);
+    theDepthStencilBits.SetValues (aFormat.cDepthBits, aFormat.cStencilBits);
+  #elif defined(HAVE_XLIB)
+    Display* aDisplay = (Display* )myDisplay;
+    XWindowAttributes aWinAttribs;
+    XGetWindowAttributes (aDisplay, (::Window )myWindow, &aWinAttribs);
+    XVisualInfo aVisInfo;
+    aVisInfo.visualid = aWinAttribs.visual->visualid;
+    aVisInfo.screen   = DefaultScreen(aDisplay);
+    int aNbItems = 0;
+    std::unique_ptr<XVisualInfo, int(*)(void*)> aVis (XGetVisualInfo (aDisplay, VisualIDMask | VisualScreenMask, &aVisInfo, &aNbItems), &XFree);
+    if (aVis.get() != NULL)
+    {
+      glXGetConfig (aDisplay, aVis.get(), GLX_RED_SIZE,     &theColorBits.r());
+      glXGetConfig (aDisplay, aVis.get(), GLX_GREEN_SIZE,   &theColorBits.g());
+      glXGetConfig (aDisplay, aVis.get(), GLX_BLUE_SIZE,    &theColorBits.b());
+      glXGetConfig (aDisplay, aVis.get(), GLX_ALPHA_SIZE,   &theColorBits.a());
+      glXGetConfig (aDisplay, aVis.get(), GLX_DEPTH_SIZE,   &theDepthStencilBits[0]);
+      glXGetConfig (aDisplay, aVis.get(), GLX_STENCIL_SIZE, &theDepthStencilBits[1]);
+    }
+  #endif
+  }
+}
+
 // =======================================================================
 // function : DiagnosticInfo
 // purpose  :
@@ -1909,6 +1968,13 @@ void OpenGl_Context::DiagnosticInformation (TColStd_IndexedDataMapOfStringString
     GLint aViewport[4] = {};
     core11fwd->glGetIntegerv (GL_VIEWPORT, aViewport);
     addInfo (theDict, "Viewport", TCollection_AsciiString() + aViewport[2] + "x" + aViewport[3]);
+
+    Graphic3d_Vec4i aWinBitsRGBA;
+    Graphic3d_Vec2i aWinBitsDepthStencil;
+    WindowBufferBits (aWinBitsRGBA, aWinBitsDepthStencil);
+    addInfo (theDict, "Window buffer",
+             TCollection_AsciiString() + "RGB" + aWinBitsRGBA.r() + " ALPHA" + aWinBitsRGBA.a()
+             + " DEPTH" + aWinBitsDepthStencil[0] + " STENCIL" + aWinBitsDepthStencil[1]);
   }
 
   if ((theFlags & Graphic3d_DiagnosticInfo_Memory) != 0)
diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx
index c7b4093305..b49f9cfcba 100644
--- a/src/OpenGl/OpenGl_Context.hxx
+++ b/src/OpenGl/OpenGl_Context.hxx
@@ -398,6 +398,10 @@ public:
   Standard_EXPORT void DiagnosticInformation (TColStd_IndexedDataMapOfStringString& theDict,
                                               Graphic3d_DiagnosticInfo theFlags) const;
 
+  //! Fetches information about window buffer pixel format.
+  Standard_EXPORT void WindowBufferBits (Graphic3d_Vec4i& theColorBits,
+                                         Graphic3d_Vec2i& theDepthStencilBits) const;
+
   //! Access shared resource by its name.
   //! @param  theKey - unique identifier;
   //! @return handle to shared resource or NULL.
@@ -565,6 +569,9 @@ public:
   //! Overrides if window/surface buffer is sRGB-ready or not (initialized with the context).
   void SetWindowSRGB (bool theIsSRgb) { myIsSRgbWindow = theIsSRgb; }
 
+  //! Returns TRUE if window/surface buffer has deep color (10bit per component / 30bit RGB) or better precision.
+  bool IsWindowDeepColor() const { return myIsWindowDeepColor; }
+
   //! Convert Quantity_ColorRGBA into vec4
   //! with conversion or no conversion into non-linear sRGB
   //! basing on ToRenderSRGB() flag.
@@ -1165,6 +1172,7 @@ private: //! @name fields tracking current state
   Standard_Boolean              myAllowAlphaToCov; //!< flag allowing   GL_SAMPLE_ALPHA_TO_COVERAGE usage
   Standard_Boolean              myAlphaToCoverage; //!< flag indicating GL_SAMPLE_ALPHA_TO_COVERAGE state
   Standard_Boolean              myIsGlDebugCtx;    //!< debug context initialization state
+  Standard_Boolean              myIsWindowDeepColor; //!< indicates that window buffer is has deep color pixel format
   Standard_Boolean              myIsSRgbWindow;    //!< indicates that window buffer is sRGB-ready
   Standard_Boolean              myIsSRgbActive;    //!< flag indicating GL_FRAMEBUFFER_SRGB state
   TCollection_AsciiString       myVendor;          //!< Graphics Driver's vendor
diff --git a/src/OpenGl/OpenGl_DepthPeeling.cxx b/src/OpenGl/OpenGl_DepthPeeling.cxx
index f89caa2976..b105a10af0 100644
--- a/src/OpenGl/OpenGl_DepthPeeling.cxx
+++ b/src/OpenGl/OpenGl_DepthPeeling.cxx
@@ -27,11 +27,11 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_DepthPeeling, OpenGl_NamedResource)
 OpenGl_DepthPeeling::OpenGl_DepthPeeling()
 : OpenGl_NamedResource ("depth_peeling")
 {
-  myDepthPeelFbosOit[0]      = new OpenGl_FrameBuffer();
-  myDepthPeelFbosOit[1]      = new OpenGl_FrameBuffer();
-  myFrontBackColorFbosOit[0] = new OpenGl_FrameBuffer();
-  myFrontBackColorFbosOit[1] = new OpenGl_FrameBuffer();
-  myBlendBackFboOit          = new OpenGl_FrameBuffer();
+  myDepthPeelFbosOit[0]      = new OpenGl_FrameBuffer (myResourceId + ":fbo0");
+  myDepthPeelFbosOit[1]      = new OpenGl_FrameBuffer (myResourceId + ":fbo1");
+  myFrontBackColorFbosOit[0] = new OpenGl_FrameBuffer (myResourceId + ":fbo0_color");
+  myFrontBackColorFbosOit[1] = new OpenGl_FrameBuffer (myResourceId + ":fbo1_color");
+  myBlendBackFboOit          = new OpenGl_FrameBuffer (myResourceId + ":fbo_blend");
 }
 
 // =======================================================================
diff --git a/src/OpenGl/OpenGl_FrameBuffer.cxx b/src/OpenGl/OpenGl_FrameBuffer.cxx
index f7a4d95a7d..2d7d0328cb 100644
--- a/src/OpenGl/OpenGl_FrameBuffer.cxx
+++ b/src/OpenGl/OpenGl_FrameBuffer.cxx
@@ -22,7 +22,7 @@
 #include <Standard_NotImplemented.hxx>
 #include <TCollection_ExtendedString.hxx>
 
-IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource)
+IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer, OpenGl_NamedResource)
 
 namespace
 {
@@ -66,8 +66,9 @@ namespace
 // function : OpenGl_FrameBuffer
 // purpose  :
 // =======================================================================
-OpenGl_FrameBuffer::OpenGl_FrameBuffer()
-: myInitVPSizeX (0),
+OpenGl_FrameBuffer::OpenGl_FrameBuffer (const TCollection_AsciiString& theResourceId)
+: OpenGl_NamedResource (theResourceId),
+  myInitVPSizeX (0),
   myInitVPSizeY (0),
   myVPSizeX (0),
   myVPSizeY (0),
@@ -79,10 +80,10 @@ OpenGl_FrameBuffer::OpenGl_FrameBuffer()
   myIsOwnBuffer (false),
   myIsOwnColor  (false),
   myIsOwnDepth  (false),
-  myDepthStencilTexture (new OpenGl_Texture())
+  myDepthStencilTexture (new OpenGl_Texture (theResourceId + ":depth_stencil"))
 {
   myColorFormats.Append (GL_RGBA8);
-  myColorTextures.Append (new OpenGl_Texture());
+  myColorTextures.Append (new OpenGl_Texture (theResourceId + ":color"));
 }
 
 // =======================================================================
@@ -221,7 +222,9 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
   }
   for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
   {
-    myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
+    myColorTextures.Append (aLength < aTextures.Length()
+                          ? aTextures.Value (aLength)
+                          : new OpenGl_Texture (myResourceId + ":color" + aLength));
   }
 
   myDepthFormat = theDepthStencilTexture->GetFormat();
@@ -343,7 +346,9 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
   }
   for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
   {
-    myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
+    myColorTextures.Append (aLength < aTextures.Length()
+                          ? aTextures.Value (aLength)
+                          : new OpenGl_Texture (myResourceId + ":color" + aLength));
   }
 
   myDepthFormat = theDepthFormat;
diff --git a/src/OpenGl/OpenGl_FrameBuffer.hxx b/src/OpenGl/OpenGl_FrameBuffer.hxx
index 3071c04cdc..d3955eca00 100644
--- a/src/OpenGl/OpenGl_FrameBuffer.hxx
+++ b/src/OpenGl/OpenGl_FrameBuffer.hxx
@@ -15,7 +15,7 @@
 #ifndef OpenGl_FrameBuffer_HeaderFile
 #define OpenGl_FrameBuffer_HeaderFile
 
-#include <OpenGl_Resource.hxx>
+#include <OpenGl_NamedResource.hxx>
 
 #include <Graphic3d_BufferType.hxx>
 #include <Graphic3d_Vec2.hxx>
@@ -25,16 +25,16 @@
 class Image_PixMap;
 class OpenGl_Texture;
 
-DEFINE_STANDARD_HANDLE(OpenGl_FrameBuffer, OpenGl_Resource)
+DEFINE_STANDARD_HANDLE(OpenGl_FrameBuffer, OpenGl_NamedResource)
 
 //! Short declaration of useful collection types.
 typedef NCollection_Vector<Standard_Integer> OpenGl_ColorFormats;
 
 //! Class implements FrameBuffer Object (FBO) resource
 //! intended for off-screen rendering.
-class OpenGl_FrameBuffer : public OpenGl_Resource
+class OpenGl_FrameBuffer : public OpenGl_NamedResource
 {
-
+  DEFINE_STANDARD_RTTIEXT(OpenGl_FrameBuffer, OpenGl_NamedResource)
 public:
 
   //! Helpful constants
@@ -57,7 +57,7 @@ public:
 public:
 
   //! Empty constructor
-  Standard_EXPORT OpenGl_FrameBuffer();
+  Standard_EXPORT OpenGl_FrameBuffer (const TCollection_AsciiString& theResourceId = TCollection_AsciiString());
 
   //! Destructor
   Standard_EXPORT virtual ~OpenGl_FrameBuffer();
@@ -371,10 +371,6 @@ protected:
   OpenGl_TextureArray    myColorTextures;       //!< color texture objects
   Handle(OpenGl_Texture) myDepthStencilTexture; //!< depth-stencil texture object
 
-public:
-
-  DEFINE_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource) // Type definition
-
 };
 
 #endif // OPENGL_FRAME_BUFFER_H
diff --git a/src/OpenGl/OpenGl_GraphicDriver.cxx b/src/OpenGl/OpenGl_GraphicDriver.cxx
index b39fd6c199..8e348d9406 100644
--- a/src/OpenGl/OpenGl_GraphicDriver.cxx
+++ b/src/OpenGl/OpenGl_GraphicDriver.cxx
@@ -79,28 +79,30 @@ namespace
 
 #if defined(HAVE_EGL)
   //! Wrapper over eglChooseConfig() called with preferred defaults.
-  static EGLConfig chooseEglSurfConfig (EGLDisplay theDisplay)
+  static EGLConfig chooseEglSurfConfig (EGLDisplay theDisplay,
+                                        const Handle(OpenGl_Caps)& theCaps)
   {
-    EGLint aConfigAttribs[] =
-    {
-      EGL_RED_SIZE,     8,
-      EGL_GREEN_SIZE,   8,
-      EGL_BLUE_SIZE,    8,
-      EGL_ALPHA_SIZE,   0,
-      EGL_DEPTH_SIZE,   24,
-      EGL_STENCIL_SIZE, 8,
-    #if defined(OpenGl_USE_GLES2)
-      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-    #else
-      EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
-    #endif
-      EGL_NONE
-    };
-
     EGLConfig aCfg = NULL;
     EGLint aNbConfigs = 0;
     for (Standard_Integer aGlesVer = 3; aGlesVer >= 2; --aGlesVer)
     {
+      bool isDeepColor = theCaps->buffersDeepColor;
+      EGLint aConfigAttribs[] =
+      {
+        EGL_RED_SIZE,     isDeepColor ? 10 : 8,
+        EGL_GREEN_SIZE,   isDeepColor ? 10 : 8,
+        EGL_BLUE_SIZE,    isDeepColor ? 10 : 8,
+        EGL_ALPHA_SIZE,   0,
+        EGL_DEPTH_SIZE,   24,
+        EGL_STENCIL_SIZE, 8,
+      #if defined(OpenGl_USE_GLES2)
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+      #else
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+      #endif
+        EGL_NONE
+      };
+
     #if defined(OpenGl_USE_GLES2)
       aConfigAttribs[6 * 2 + 1] = aGlesVer == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT;
     #else
@@ -117,13 +119,30 @@ namespace
       }
       eglGetError();
 
-      aConfigAttribs[4 * 2 + 1] = 16; // try config with smaller depth buffer
-      if (eglChooseConfig (theDisplay, aConfigAttribs, &aCfg, 1, &aNbConfigs) == EGL_TRUE
-       && aCfg != NULL)
+      if (isDeepColor)
       {
-        return aCfg;
+        // try config with smaller color buffer
+        aConfigAttribs[0 * 2 + 1] = 8;
+        aConfigAttribs[1 * 2 + 1] = 8;
+        aConfigAttribs[2 * 2 + 1] = 8;
+        if (eglChooseConfig (theDisplay, aConfigAttribs, &aCfg, 1, &aNbConfigs) == EGL_TRUE
+         && aCfg != NULL)
+        {
+          return aCfg;
+        }
+        eglGetError();
+      }
+
+      {
+        // try config with smaller depth buffer
+        aConfigAttribs[4 * 2 + 1] = 16;
+        if (eglChooseConfig (theDisplay, aConfigAttribs, &aCfg, 1, &aNbConfigs) == EGL_TRUE
+         && aCfg != NULL)
+        {
+          return aCfg;
+        }
+        eglGetError();
       }
-      eglGetError();
     }
     return aCfg;
   }
@@ -327,7 +346,7 @@ Standard_Boolean OpenGl_GraphicDriver::InitContext()
     return Standard_False;
   }
 
-  myEglConfig = chooseEglSurfConfig ((EGLDisplay )myEglDisplay);
+  myEglConfig = chooseEglSurfConfig ((EGLDisplay )myEglDisplay, myCaps);
   if (myEglConfig == NULL)
   {
     ::Message::SendFail ("Error: EGL does not provide compatible configurations");
@@ -404,7 +423,7 @@ Standard_Boolean OpenGl_GraphicDriver::InitEglContext (Aspect_Display          t
   myEglConfig  = theEglConfig;
   if (theEglConfig == NULL)
   {
-    myEglConfig = chooseEglSurfConfig ((EGLDisplay )myEglDisplay);
+    myEglConfig = chooseEglSurfConfig ((EGLDisplay )myEglDisplay, myCaps);
     if (myEglConfig == NULL)
     {
       ::Message::SendFail ("Error: EGL does not provide compatible configurations");
diff --git a/src/OpenGl/OpenGl_ShadowMap.cxx b/src/OpenGl/OpenGl_ShadowMap.cxx
index fa803e97f1..f56f2241ab 100644
--- a/src/OpenGl/OpenGl_ShadowMap.cxx
+++ b/src/OpenGl/OpenGl_ShadowMap.cxx
@@ -29,7 +29,7 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShadowMap, OpenGl_NamedResource)
 // =======================================================================
 OpenGl_ShadowMap::OpenGl_ShadowMap()
 : OpenGl_NamedResource ("shadow_map"),
-  myShadowMapFbo (new OpenGl_FrameBuffer()),
+  myShadowMapFbo (new OpenGl_FrameBuffer (myResourceId + ":fbo")),
   myShadowCamera (new Graphic3d_Camera()),
   myShadowMapBias (0.0f)
 {
diff --git a/src/OpenGl/OpenGl_TextureFormat.cxx b/src/OpenGl/OpenGl_TextureFormat.cxx
index 5fcc450efd..31f62cc39f 100644
--- a/src/OpenGl/OpenGl_TextureFormat.cxx
+++ b/src/OpenGl/OpenGl_TextureFormat.cxx
@@ -110,6 +110,7 @@ TCollection_AsciiString OpenGl_TextureFormat::FormatDataType (GLint theDataType)
     case GL_HALF_FLOAT:        return "GL_HALF_FLOAT";
     case 0x8D61:               return "GL_HALF_FLOAT_OES";
     case GL_UNSIGNED_INT_24_8: return "GL_UNSIGNED_INT_24_8";
+    case GL_UNSIGNED_INT_2_10_10_10_REV:    return "GL_UNSIGNED_INT_2_10_10_10_REV";
     case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return "GL_FLOAT_32_UNSIGNED_INT_24_8_REV";
   }
   return OpenGl_Context::FormatGlEnumHex (theDataType);
@@ -586,6 +587,15 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_
       }
       return aFormat;
     }
+    case GL_RGB10_A2:
+    {
+      aFormat.SetNbComponents (4);
+      aFormat.SetInternalFormat (theSizedFormat);
+      aFormat.SetPixelFormat (GL_RGBA);
+      aFormat.SetDataType (GL_UNSIGNED_INT_2_10_10_10_REV);
+      aFormat.SetImageFormat (Image_Format_RGBA);
+      return aFormat;
+    }
     // integer types
     case GL_R32I:
     {
diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx
index 819491c3e6..d398a4a9ec 100644
--- a/src/OpenGl/OpenGl_View.cxx
+++ b/src/OpenGl/OpenGl_View.cxx
@@ -158,21 +158,21 @@ OpenGl_View::OpenGl_View (const Handle(Graphic3d_StructureManager)& theMgr,
   myNoShadingLight = new Graphic3d_LightSet();
   myNoShadingLight->Add (aLight);
 
-  myMainSceneFbos[0]         = new OpenGl_FrameBuffer();
-  myMainSceneFbos[1]         = new OpenGl_FrameBuffer();
-  myMainSceneFbosOit[0]      = new OpenGl_FrameBuffer();
-  myMainSceneFbosOit[1]      = new OpenGl_FrameBuffer();
-  myImmediateSceneFbos[0]    = new OpenGl_FrameBuffer();
-  myImmediateSceneFbos[1]    = new OpenGl_FrameBuffer();
-  myImmediateSceneFbosOit[0] = new OpenGl_FrameBuffer();
-  myImmediateSceneFbosOit[1] = new OpenGl_FrameBuffer();
-  myXrSceneFbo               = new OpenGl_FrameBuffer();
-  myOpenGlFBO                = new OpenGl_FrameBuffer();
-  myOpenGlFBO2               = new OpenGl_FrameBuffer();
-  myRaytraceFBO1[0]          = new OpenGl_FrameBuffer();
-  myRaytraceFBO1[1]          = new OpenGl_FrameBuffer();
-  myRaytraceFBO2[0]          = new OpenGl_FrameBuffer();
-  myRaytraceFBO2[1]          = new OpenGl_FrameBuffer();
+  myMainSceneFbos[0]         = new OpenGl_FrameBuffer ("fbo0_main");
+  myMainSceneFbos[1]         = new OpenGl_FrameBuffer ("fbo1_main");
+  myMainSceneFbosOit[0]      = new OpenGl_FrameBuffer ("fbo0_main_oit");
+  myMainSceneFbosOit[1]      = new OpenGl_FrameBuffer ("fbo1_main_oit");
+  myImmediateSceneFbos[0]    = new OpenGl_FrameBuffer ("fbo0_imm");
+  myImmediateSceneFbos[1]    = new OpenGl_FrameBuffer ("fbo1_imm");
+  myImmediateSceneFbosOit[0] = new OpenGl_FrameBuffer ("fbo0_imm_oit");
+  myImmediateSceneFbosOit[1] = new OpenGl_FrameBuffer ("fbo1_imm_oit");
+  myXrSceneFbo               = new OpenGl_FrameBuffer ("fbo_xr");
+  myOpenGlFBO                = new OpenGl_FrameBuffer ("fbo_gl");
+  myOpenGlFBO2               = new OpenGl_FrameBuffer ("fbo_gl2");
+  myRaytraceFBO1[0]          = new OpenGl_FrameBuffer ("fbo0_raytrace1");
+  myRaytraceFBO1[1]          = new OpenGl_FrameBuffer ("fbo1_raytrace1");
+  myRaytraceFBO2[0]          = new OpenGl_FrameBuffer ("fbo0_raytrace2");
+  myRaytraceFBO2[1]          = new OpenGl_FrameBuffer ("fbo1_raytrace2");
   myDepthPeelingFbos = new OpenGl_DepthPeeling();
   myShadowMaps = new OpenGl_ShadowMapArray();
 }
@@ -387,8 +387,25 @@ void OpenGl_View::SetWindow (const Handle(Aspect_Window)& theWindow,
   myHasFboBlit = Standard_True;
   Invalidate();
 
+  // choose preferred FBO format
+  const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
+  if (aCtx->IsWindowDeepColor()
+   && aCtx->IsGlGreaterEqual (3, 0))
+  {
+    myFboColorFormat = GL_RGB10_A2;
+  }
+  else if (aCtx->HasSRGB())
+  {
+    // note that GL_SRGB8 is not required to be renderable, unlike GL_RGB8, GL_RGBA8, GL_SRGB8_ALPHA8
+    myFboColorFormat = GL_SRGB8_ALPHA8;
+  }
+  else
+  {
+    myFboColorFormat = GL_RGBA8;
+  }
+
   // Environment texture resource does not support lazy initialization.
-  initTextureEnv (myWorkspace->GetGlContext());
+  initTextureEnv (aCtx);
 }
 
 // =======================================================================
@@ -950,6 +967,19 @@ void OpenGl_View::DiagnosticInformation (TColStd_IndexedDataMapOfStringString& t
   {
     TCollection_AsciiString aResRatio (myRenderParams.ResolutionRatio());
     theDict.ChangeFromIndex (theDict.Add ("ResolutionRatio", aResRatio)) = aResRatio;
+    if (myMainSceneFbos[0]->IsValid())
+    {
+      TCollection_AsciiString anFboInfo;
+      if (const Handle(OpenGl_Texture)& aColorTex = myMainSceneFbos[0]->ColorTexture())
+      {
+        anFboInfo += OpenGl_TextureFormat::FormatFormat (aColorTex->SizedFormat());
+      }
+      if (const Handle(OpenGl_Texture)& aDepthTex = myMainSceneFbos[0]->DepthStencilTexture())
+      {
+        anFboInfo = anFboInfo + " " + OpenGl_TextureFormat::FormatFormat (aDepthTex->SizedFormat());
+      }
+      theDict.ChangeFromIndex (theDict.Add ("FBO buffer", anFboInfo)) = anFboInfo;
+    }
   }
 }
 
diff --git a/src/OpenGl/OpenGl_Window.cxx b/src/OpenGl/OpenGl_Window.cxx
index 788aa3553e..16545d39fc 100644
--- a/src/OpenGl/OpenGl_Window.cxx
+++ b/src/OpenGl/OpenGl_Window.cxx
@@ -340,7 +340,7 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
     HWND  aWinTmp     = NULL;
     HDC   aDevCtxTmp  = NULL;
     HGLRC aRendCtxTmp = NULL;
-    if ((!theCaps->contextDebug && !theCaps->contextNoAccel && theCaps->contextCompatible)
+    if ((!theCaps->contextDebug && !theCaps->contextNoAccel && theCaps->contextCompatible && !theCaps->buffersDeepColor)
      || RegisterClassW (&aClass) == 0)
     {
       aClass.lpszClassName = NULL;
@@ -404,7 +404,11 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
         WGL_PIXEL_TYPE_ARB,     WGL_TYPE_RGBA_ARB,
         //WGL_SAMPLE_BUFFERS_ARB, 1,
         //WGL_SAMPLES_ARB,        8,
-        WGL_COLOR_BITS_ARB,     24,
+        //WGL_COLOR_BITS_ARB,     24,
+        WGL_RED_BITS_ARB,   theCaps->buffersDeepColor ? 10 : 8,
+        WGL_GREEN_BITS_ARB, theCaps->buffersDeepColor ? 10 : 8,
+        WGL_BLUE_BITS_ARB,  theCaps->buffersDeepColor ? 10 : 8,
+        WGL_ALPHA_BITS_ARB, theCaps->buffersDeepColor ? 2  : 8,
         WGL_DEPTH_BITS_ARB,     24,
         WGL_STENCIL_BITS_ARB,   8,
         // WGL_EXT_colorspace extension specifies if OpenGL should write into window buffer as into sRGB or RGB framebuffer
@@ -415,7 +419,12 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
         0, 0,
       };
       unsigned int aFrmtsNb = 0;
-      aChoosePixProc (aWindowDC, aPixAttribs, NULL, 1, &aPixelFrmtId, &aFrmtsNb);
+      if (!aChoosePixProc (aWindowDC, aPixAttribs, NULL, 1, &aPixelFrmtId, &aFrmtsNb)
+        && theCaps->buffersDeepColor)
+      {
+        /// TODO
+        Message::SendFail() << "Error: unable to find RGB10_A2 window buffer format!";
+      }
     }
 
     // setup pixel format - may be set only once per window
diff --git a/src/OpenGlTest/OpenGlTest_Commands.cxx b/src/OpenGlTest/OpenGlTest_Commands.cxx
index be6785cf38..226b6e44b2 100644
--- a/src/OpenGlTest/OpenGlTest_Commands.cxx
+++ b/src/OpenGlTest/OpenGlTest_Commands.cxx
@@ -597,6 +597,7 @@ static int VCaps (Draw_Interpretor& theDI,
     theDI << "Stereo:  " << (aCaps->contextStereo ? "1" : "0") << "\n";
     theDI << "WinBuffer: " << (aCaps->useSystemBuffer ? "1" : "0") << "\n";
     theDI << "OpaqueAlpha: " << (aCaps->buffersOpaqueAlpha ? "1" : "0") << "\n";
+    theDI << "DeepColor: " << (aCaps->buffersDeepColor ? "1" : "0") << "\n";
     theDI << "NoExt:"    << (aCaps->contextNoExtensions ? "1" : "0") << "\n";
     theDI << "MaxVersion:" << aCaps->contextMajorVersionUpper << "." << aCaps->contextMinorVersionUpper << "\n";
     theDI << "CompressTextures: " << (aCaps->compressedTexturesDisable ? "0" : "1") << "\n";
@@ -614,148 +615,90 @@ static int VCaps (Draw_Interpretor& theDI,
       continue;
     }
     else if (anArgCase == "-vsync"
+          || anArgCase == "-novsync"
           || anArgCase == "-swapinterval")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->swapInterval = toEnable;
+      aCaps->swapInterval = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
     }
-    else if (anArgCase == "-ffp")
+    else if (anArgCase == "-ffp"
+          || anArgCase == "-noffp")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->ffpEnable = toEnable;
+      aCaps->ffpEnable = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
     }
-    else if (anArgCase == "-polygonmode")
+    else if (anArgCase == "-polygonmode"
+          || anArgCase == "-nopolygonmode")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->usePolygonMode = toEnable;
+      aCaps->usePolygonMode = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
     }
-    else if (anArgCase == "-srgb")
+    else if (anArgCase == "-srgb"
+          || anArgCase == "-nosrgb")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->sRGBDisable = !toEnable;
+      aCaps->sRGBDisable = !Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
     }
-    else if (anArgCase == "-compressedtextures")
+    else if (anArgCase == "-compressedtextures"
+          || anArgCase == "-nocompressedtextures")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->compressedTexturesDisable = !toEnable;
+      aCaps->compressedTexturesDisable = !Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
     }
-    else if (anArgCase == "-vbo")
+    else if (anArgCase == "-vbo"
+          || anArgCase == "-novbo")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->vboDisable = !toEnable;
+      aCaps->vboDisable = !Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
     }
     else if (anArgCase == "-sprite"
           || anArgCase == "-sprites")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->pntSpritesDisable = !toEnable;
+      aCaps->pntSpritesDisable = !Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
     }
     else if (anArgCase == "-depthzerotoone"
           || anArgCase == "-zerotoonedepth"
           || anArgCase == "-usezerotoonedepth"
           || anArgCase == "-iszerotoonedepth")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->useZeroToOneDepth = toEnable;
+      aCaps->useZeroToOneDepth = Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
     }
-    else if (anArgCase == "-softmode")
+    else if (anArgCase == "-softmode"
+          || anArgCase == "-contextnoaccel")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->contextNoAccel = toEnable;
+      aCaps->contextNoAccel = Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
     }
     else if (anArgCase == "-opaquealpha"
-          || anArgCase == "-buffersOpaqueAlpha")
+          || anArgCase == "-noopaquealpha"
+          || anArgCase == "-buffersopaquealpha"
+          || anArgCase == "-nobuffersopaquealpha")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->buffersOpaqueAlpha = toEnable;
+      aCaps->buffersOpaqueAlpha = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
+    }
+    else if (anArgCase == "-deepcolor"
+          || anArgCase == "-nodeepcolor"
+          || anArgCase == "-buffersdeepcolor"
+          || anArgCase == "-nobuffersdeepcolor")
+    {
+      aCaps->buffersDeepColor = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
     }
     else if (anArgCase == "-winbuffer"
           || anArgCase == "-windowbuffer"
+          || anArgCase == "-nowinbuffer"
+          || anArgCase == "-nowindowbuffer"
           || anArgCase == "-usewinbuffer"
           || anArgCase == "-usewindowbuffer"
           || anArgCase == "-usesystembuffer")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->useSystemBuffer = toEnable;
+      aCaps->useSystemBuffer = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
     }
     else if (anArgCase == "-accel"
-          || anArgCase == "-acceleration")
+          || anArgCase == "-acceleration"
+          || anArgCase == "-noaccel"
+          || anArgCase == "-noacceleration")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->contextNoAccel = !toEnable;
+      aCaps->contextNoAccel = !Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
     }
     else if (anArgCase == "-compat"
           || anArgCase == "-compatprofile"
           || anArgCase == "-compatible"
           || anArgCase == "-compatibleprofile")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->contextCompatible = toEnable;
+      aCaps->contextCompatible = Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
       if (!aCaps->contextCompatible)
       {
         aCaps->ffpEnable = Standard_False;
@@ -764,40 +707,24 @@ static int VCaps (Draw_Interpretor& theDI,
     else if (anArgCase == "-core"
           || anArgCase == "-coreprofile")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->contextCompatible = !toEnable;
+      aCaps->contextCompatible = !Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
       if (!aCaps->contextCompatible)
       {
         aCaps->ffpEnable = Standard_False;
       }
     }
     else if (anArgCase == "-stereo"
-          || anArgCase == "-quadbuffer")
+          || anArgCase == "-quadbuffer"
+          || anArgCase == "-nostereo"
+          || anArgCase == "-noquadbuffer")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
-      {
-        --anArgIter;
-      }
-      aCaps->contextStereo = toEnable;
+      aCaps->contextStereo = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
     }
     else if (anArgCase == "-noext"
           || anArgCase == "-noextensions"
           || anArgCase == "-noextension")
     {
-      Standard_Boolean toDisable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !Draw::ParseOnOff (theArgVec[anArgIter], toDisable))
-      {
-        --anArgIter;
-      }
-      aCaps->contextNoExtensions = toDisable;
+      aCaps->contextNoExtensions = Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
     }
     else if (anArgCase == "-maxversion"
           || anArgCase == "-upperversion"
@@ -859,7 +786,7 @@ void OpenGlTest::Commands (Draw_Interpretor& theCommands)
             "vcaps [-sRGB {0|1}] [-vbo {0|1}] [-sprites {0|1}] [-ffp {0|1}] [-polygonMode {0|1}]"
     "\n\t\t:       [-compatibleProfile {0|1}] [-compressedTextures {0|1}]"
     "\n\t\t:       [-vsync {0|1}] [-useWinBuffer {0|1}] [-opaqueAlpha {0|1}]"
-    "\n\t\t:       [-quadBuffer {0|1}] [-stereo {0|1}]"
+    "\n\t\t:       [-deepColor {0|1}] [-quadBuffer {0|1}] [-stereo {0|1}]"
     "\n\t\t:       [-softMode {0|1}] [-noupdate|-update]"
     "\n\t\t:       [-zeroToOneDepth {0|1}]"
     "\n\t\t:       [-noExtensions {0|1}] [-maxVersion Major Minor]"
@@ -877,10 +804,12 @@ void OpenGlTest::Commands (Draw_Interpretor& theCommands)
     "\n\t\t:  opaqueAlpha - disable writes in alpha component of color buffer"
     "\n\t\t:  winBuffer - allow using window buffer for rendering"
     "\n\t\t:  zeroToOneDepth - use [0,1] depth range instead of [-1,1] range"
+    "\n\t\t: Window buffer creation options:"
+    "\n\t\t:  quadbuffer  - QuadBuffer for stereoscopic displays"
+    "\n\t\t:  deepColor   - window buffer with higher color precision (30bit instead of 24bit RGB)"
     "\n\t\t: Context creation options:"
     "\n\t\t:  softMode          - software OpenGL implementation"
     "\n\t\t:  compatibleProfile - backward-compatible profile"
-    "\n\t\t:  quadbuffer        - QuadBuffer"
     "\n\t\t:  noExtensions      - disallow usage of extensions"
     "\n\t\t:  maxVersion        - force upper OpenGL version to be used"
     "\n\t\t: These parameters control alternative"