0030748: Visualization - Marker displayed in immediate layer ruins QT Quick view...
[occt.git] / src / OpenGl / OpenGl_FrameBuffer.cxx
index deebed3..a3fa54f 100644 (file)
@@ -3,8 +3,8 @@
 //
 // 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 version 2.1 as published
+// 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.
 // commercial license or contractual agreement.
 
 #include <OpenGl_FrameBuffer.hxx>
+#include <OpenGl_ArbFBO.hxx>
 
+#include <NCollection_AlignedAllocator.hxx>
 #include <Standard_Assert.hxx>
+#include <TCollection_ExtendedString.hxx>
 
-IMPLEMENT_STANDARD_HANDLE (OpenGl_FrameBuffer, OpenGl_Resource)
-IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer, OpenGl_Resource)
+IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource)
 
-static inline bool isOddNumber (const GLsizei theNumber)
+namespace
 {
-  return theNumber & 0x01;
+  //! Checks whether two format arrays are equal or not.
+  static bool operator== (const OpenGl_ColorFormats& theFmt1,
+                          const OpenGl_ColorFormats& theFmt2)
+  {
+    if (theFmt1.Length() != theFmt2.Length())
+      return false;
+    OpenGl_ColorFormats::Iterator anIt1 (theFmt1);
+    OpenGl_ColorFormats::Iterator anIt2 (theFmt1);
+    for (; anIt1.More(); anIt1.Next(), anIt2.Next())
+    {
+      if (anIt1.Value() != anIt2.Value())
+        return false;
+    }
+    return true;
+  }
 }
 
-static inline GLsizei getEvenNumber (const GLsizei theNumber)
+// =======================================================================
+// function : getDepthDataFormat
+// purpose  :
+// =======================================================================
+bool OpenGl_FrameBuffer::getDepthDataFormat (GLint   theTextFormat,
+                                             GLenum& thePixelFormat,
+                                             GLenum& theDataType)
 {
-  return isOddNumber (theNumber) ? (theNumber + 1) : theNumber;
+  switch (theTextFormat)
+  {
+    case GL_DEPTH24_STENCIL8:
+    {
+      thePixelFormat = GL_DEPTH_STENCIL;
+      theDataType    = GL_UNSIGNED_INT_24_8;
+      return true;
+    }
+    case GL_DEPTH32F_STENCIL8:
+    {
+      thePixelFormat = GL_DEPTH_STENCIL;
+      theDataType    = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
+      return true;
+    }
+    case GL_DEPTH_COMPONENT16:
+    {
+      thePixelFormat = GL_DEPTH_COMPONENT;
+      theDataType    = GL_UNSIGNED_SHORT;
+      return true;
+    }
+    case GL_DEPTH_COMPONENT24:
+    {
+      thePixelFormat = GL_DEPTH_COMPONENT;
+      theDataType    = GL_UNSIGNED_INT;
+      return true;
+    }
+    case GL_DEPTH_COMPONENT32F:
+    {
+      thePixelFormat = GL_DEPTH_COMPONENT;
+      theDataType    = GL_FLOAT;
+      return true;
+    }
+  }
+  return false;
 }
 
-//! Notice - 0 is not power of two here
-static inline bool isPowerOfTwo (const GLsizei theNumber)
+// =======================================================================
+// function : getColorDataFormat
+// purpose  :
+// =======================================================================
+bool OpenGl_FrameBuffer::getColorDataFormat (const Handle(OpenGl_Context)& theGlContext,
+                                             GLint   theTextFormat,
+                                             GLenum& thePixelFormat,
+                                             GLenum& theDataType)
 {
-       return !(theNumber & (theNumber - 1));
+  switch (theTextFormat)
+  {
+    case GL_RGBA32F:
+    {
+      thePixelFormat = GL_RGBA;
+      theDataType    = GL_FLOAT;
+      return true;
+    }
+    case GL_R32F:
+    {
+      thePixelFormat = GL_RED;
+      theDataType    = GL_FLOAT;
+      return true;
+    }
+    case GL_RGBA16F:
+    {
+      thePixelFormat = GL_RGBA;
+      theDataType    = GL_HALF_FLOAT;
+      if (theGlContext->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
+      {
+      #if defined(GL_ES_VERSION_2_0)
+        theDataType = GL_HALF_FLOAT_OES;
+      #else
+        theDataType = GL_FLOAT;
+      #endif
+      }
+      return true;
+    }
+    case GL_R16F:
+    {
+      thePixelFormat = GL_RED;
+      theDataType    = GL_HALF_FLOAT;
+      if (theGlContext->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
+      {
+      #if defined(GL_ES_VERSION_2_0)
+        theDataType = GL_HALF_FLOAT_OES;
+      #else
+        theDataType = GL_FLOAT;
+      #endif
+      }
+      return true;
+    }
+    case GL_RGBA8:
+    case GL_RGBA:
+    {
+      thePixelFormat = GL_RGBA;
+      theDataType    = GL_UNSIGNED_BYTE;
+      return true;
+    }
+    case GL_RGB8:
+    case GL_RGB:
+    {
+      thePixelFormat = GL_RGB;
+      theDataType = GL_UNSIGNED_BYTE;
+      return true;
+    }
+  }
+  return false;
 }
 
 // =======================================================================
 // function : OpenGl_FrameBuffer
 // purpose  :
 // =======================================================================
-OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
-: mySizeX (0),
-  mySizeY (0),
+OpenGl_FrameBuffer::OpenGl_FrameBuffer()
+: myInitVPSizeX (0),
+  myInitVPSizeY (0),
   myVPSizeX (0),
   myVPSizeY (0),
-  myTextFormat (theTextureFormat),
-  myGlTextureId (NO_TEXTURE),
+  myNbSamples (0),
+  myDepthFormat (GL_DEPTH24_STENCIL8),
   myGlFBufferId (NO_FRAMEBUFFER),
-  myGlDepthRBId (NO_RENDERBUFFER),
-  myGlStencilRBId (NO_RENDERBUFFER)
+  myGlColorRBufferId (NO_RENDERBUFFER),
+  myGlDepthRBufferId (NO_RENDERBUFFER),
+  myIsOwnBuffer  (false),
+  myIsOwnDepth  (false),
+  myDepthStencilTexture (new OpenGl_Texture())
 {
-  //
+  myColorFormats.Append (GL_RGBA8);
+  myColorTextures.Append (new OpenGl_Texture());
 }
 
 // =======================================================================
@@ -67,206 +189,586 @@ OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
 // purpose  :
 // =======================================================================
 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
-                                           const GLsizei   theViewportSizeX,
-                                           const GLsizei   theViewportSizeY,
-                                           const GLboolean toForcePowerOfTwo)
+                                           const GLsizei                 theSizeX,
+                                           const GLsizei                 theSizeY,
+                                           const GLint                   theColorFormat,
+                                           const GLint                   theDepthFormat,
+                                           const GLsizei                 theNbSamples)
+{
+  OpenGl_ColorFormats aColorFormats;
+
+  aColorFormats.Append (theColorFormat);
+
+  return Init (theGlContext, theSizeX, theSizeY, aColorFormats, theDepthFormat, theNbSamples);
+}
+
+// =======================================================================
+// function : Init
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
+                                           const GLsizei                 theSizeX,
+                                           const GLsizei                 theSizeY,
+                                           const OpenGl_ColorFormats&    theColorFormats,
+                                           const Handle(OpenGl_Texture)& theDepthStencilTexture,
+                                           const GLsizei                 theNbSamples)
 {
-  if (theGlContext->extFBO == NULL)
+  myColorFormats = theColorFormats;
+
+  OpenGl_TextureArray aTextures (myColorTextures);
+  if (!myColorTextures.IsEmpty())
+  {
+    for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
+    {
+      aTextureIt.Value()->Release (theGlContext.operator->());
+    }
+    myColorTextures.Clear();
+  }
+  for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
+  {
+    myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
+  }
+
+  myDepthFormat = theDepthStencilTexture->GetFormat();
+  myNbSamples   = theNbSamples;
+  if (theGlContext->arbFBO == NULL)
   {
     return Standard_False;
   }
 
   // clean up previous state
   Release (theGlContext.operator->());
+  if (myColorFormats.IsEmpty()
+   && myDepthFormat == 0)
+  {
+    return Standard_False;
+  }
+
+  myDepthStencilTexture = theDepthStencilTexture;
+  myIsOwnDepth  = false;
+  myIsOwnBuffer = true;
 
-  // upscale width/height if numbers are odd
-  if (toForcePowerOfTwo)
+  // setup viewport sizes as is
+  myVPSizeX = theSizeX;
+  myVPSizeY = theSizeY;
+  const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
+  const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
+
+  // Create the textures (will be used as color buffer and depth-stencil buffer)
+  if (theNbSamples != 0)
   {
-    mySizeX = OpenGl_Context::GetPowerOfTwo (theViewportSizeX, theGlContext->MaxTextureSize());
-    mySizeY = OpenGl_Context::GetPowerOfTwo (theViewportSizeY, theGlContext->MaxTextureSize());
+    for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+    {
+      const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+      const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
+      if (aColorFormat != 0
+      && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples,
+                                            aColorFormat, aSizeX, aSizeY))
+      {
+        Release (theGlContext.operator->());
+        return Standard_False;
+      }
+    }
   }
   else
   {
-    mySizeX = getEvenNumber (theViewportSizeX);
-    mySizeY = getEvenNumber (theViewportSizeY);
+    for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+    {
+      GLenum aPixelFormat = 0;
+      GLenum aDataType    = 0;
+      const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+      const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
+      if (aColorFormat != 0
+      &&  getColorDataFormat (theGlContext, aColorFormat, aPixelFormat, aDataType)
+      && !aColorTexture->Init (theGlContext, aColorFormat,
+                               aPixelFormat, aDataType,
+                               aSizeX, aSizeY, Graphic3d_TOT_2D))
+      {
+        Release (theGlContext.operator->());
+        return Standard_False;
+      }
+    }
   }
 
-  // setup viewport sizes as is
-  myVPSizeX = theViewportSizeX;
-  myVPSizeY = theViewportSizeY;
+  // Build FBO and setup it as texture
+  theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
+  theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
 
-  // Create the texture (will be used as color buffer)
-  if (!initTrashTexture (theGlContext))
+  for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
   {
-    if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
+    const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+    if (aColorTexture->IsValid())
     {
-      return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
+      theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
+                                                    aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
     }
+  }
+  if (myDepthStencilTexture->IsValid())
+  {
+  #ifdef GL_DEPTH_STENCIL_ATTACHMENT
+    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+  #else
+    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+  #endif
+  }
+  if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+  {
     Release (theGlContext.operator->());
     return Standard_False;
   }
 
-  if (!theGlContext->extPDS)
+  UnbindBuffer (theGlContext);
+  return Standard_True;
+}
+
+// =======================================================================
+// function : Init
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
+                                           const GLsizei                 theSizeX,
+                                           const GLsizei                 theSizeY,
+                                           const OpenGl_ColorFormats&    theColorFormats,
+                                           const GLint                   theDepthFormat,
+                                           const GLsizei                 theNbSamples)
+{
+  myColorFormats = theColorFormats;
+
+  OpenGl_TextureArray aTextures (myColorTextures);
+  if (!myColorTextures.IsEmpty())
+  {
+    for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
+    {
+      aTextureIt.Value()->Release (theGlContext.operator->());
+    }
+    myColorTextures.Clear();
+  }
+  for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
   {
-    // Create RenderBuffer to be used as depth buffer
-    theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId);
-    theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
-    theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, mySizeX, mySizeY);
+    myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
+  }
+
+  myDepthFormat = theDepthFormat;
+  myNbSamples   = theNbSamples;
+  myInitVPSizeX = theSizeX;
+  myInitVPSizeY = theSizeY;
+  if (theGlContext->arbFBO == NULL)
+  {
+    return Standard_False;
+  }
 
-    // Create RenderBuffer to be used as stencil buffer
-    theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlStencilRBId);
-    theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlStencilRBId);
-    theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, mySizeX, mySizeY);
+  // clean up previous state
+  Release (theGlContext.operator->());
+  if (myColorFormats.IsEmpty()
+   && myDepthFormat == 0)
+  {
+    return Standard_False;
+  }
+
+  myIsOwnBuffer = true;
+  myIsOwnDepth  = true;
+
+  // setup viewport sizes as is
+  myVPSizeX = theSizeX;
+  myVPSizeY = theSizeY;
+  const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
+  const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
+  bool hasStencilRB = false;
+
+  // Create the textures (will be used as color buffer and depth-stencil buffer)
+  if (theNbSamples != 0)
+  {
+    for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+    {
+      const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+      const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
+      if (aColorFormat != 0
+      && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY))
+      {
+        Release (theGlContext.operator->());
+        return Standard_False;
+      }
+    }
+    if (myDepthFormat != 0
+    && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
+    {
+      Release (theGlContext.operator->());
+      return Standard_False;
+    }
   }
   else
   {
-    // Create combined depth stencil buffer
-    theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId);
-    theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
-    theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, mySizeX, mySizeY);
-    myGlStencilRBId = myGlDepthRBId;
+    GLenum aPixelFormat = 0;
+    GLenum aDataType    = 0;
+
+    for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+    {
+      const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+      const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
+      if (aColorFormat != 0
+      &&  getColorDataFormat (theGlContext, aColorFormat, aPixelFormat, aDataType)
+      && !aColorTexture->Init (theGlContext, aColorFormat,
+                               aPixelFormat, aDataType,
+                               aSizeX, aSizeY, Graphic3d_TOT_2D))
+      {
+        Release (theGlContext.operator->());
+        return Standard_False;
+      }
+    }
+
+    // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
+    // instead of just trying to create such texture
+    if (myDepthFormat != 0
+    &&  getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType)
+    && !myDepthStencilTexture->Init (theGlContext, myDepthFormat,
+                                      aPixelFormat, aDataType,
+                                      aSizeX, aSizeY, Graphic3d_TOT_2D))
+    {
+      TCollection_ExtendedString aMsg = TCollection_ExtendedString()
+        + "Warning! Depth textures are not supported by hardware!";
+      theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
+                                 GL_DEBUG_TYPE_PORTABILITY,
+                                 0,
+                                 GL_DEBUG_SEVERITY_HIGH,
+                                 aMsg);
+
+      hasStencilRB = aPixelFormat == GL_DEPTH_STENCIL
+                  && theGlContext->extPDS;
+      GLint aDepthStencilFormat = hasStencilRB
+                                ? GL_DEPTH24_STENCIL8
+                                : GL_DEPTH_COMPONENT16;
+
+      theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
+      theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
+      theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, aDepthStencilFormat, aSizeX, aSizeY);
+      theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+    }
   }
 
   // Build FBO and setup it as texture
-  theGlContext->extFBO->glGenFramebuffersEXT (1, &myGlFBufferId);
-  theGlContext->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
-  glEnable (GL_TEXTURE_2D);
-  glBindTexture (GL_TEXTURE_2D, myGlTextureId);
-  theGlContext->extFBO->glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, myGlTextureId, 0);
-  theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlDepthRBId);
-  theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlStencilRBId);
-  if (theGlContext->extFBO->glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
-  {
-    if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
+  theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
+  theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
+  for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+  {
+    const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+    if (aColorTexture->IsValid())
     {
-      return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
+      theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
+                                                    aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
     }
+  }
+  if (myDepthStencilTexture->IsValid())
+  {
+  #ifdef GL_DEPTH_STENCIL_ATTACHMENT
+    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+  #else
+    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+  #endif
+  }
+  else if (myGlDepthRBufferId != NO_RENDERBUFFER)
+  {
+  #ifdef GL_DEPTH_STENCIL_ATTACHMENT
+    theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
+                                                     GL_RENDERBUFFER, myGlDepthRBufferId);
+  #else
+    theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                                     GL_RENDERBUFFER, myGlDepthRBufferId);
+    if (hasStencilRB)
+    {
+      theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                                       GL_RENDERBUFFER, myGlDepthRBufferId);
+    }
+  #endif
+  }
+  if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+  {
     Release (theGlContext.operator->());
     return Standard_False;
   }
 
-  UnbindBuffer  (theGlContext);
-  UnbindTexture (theGlContext);
-  theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, NO_RENDERBUFFER);
+  UnbindBuffer (theGlContext);
   return Standard_True;
 }
 
 // =======================================================================
-// function : Release
+// function : InitLazy
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
+                                               const GLsizei                 theViewportSizeX,
+                                               const GLsizei                 theViewportSizeY,
+                                               const GLint                   theColorFormat,
+                                               const GLint                   theDepthFormat,
+                                               const GLsizei                 theNbSamples)
+{
+  OpenGl_ColorFormats aColorFormats;
+
+  aColorFormats.Append (theColorFormat);
+
+  return InitLazy (theGlContext, theViewportSizeX, theViewportSizeY, aColorFormats, theDepthFormat, theNbSamples);
+}
+
+// =======================================================================
+// function : InitLazy
 // purpose  :
 // =======================================================================
-void OpenGl_FrameBuffer::Release (const OpenGl_Context* theGlCtx)
+Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
+                                               const GLsizei                 theViewportSizeX,
+                                               const GLsizei                 theViewportSizeY,
+                                               const OpenGl_ColorFormats&    theColorFormats,
+                                               const GLint                   theDepthFormat,
+                                               const GLsizei                 theNbSamples)
 {
-  if (isValidDepthBuffer()
-   || isValidStencilBuffer()
-   || isValidTexture()
-   || isValidFrameBuffer())
+  if (myVPSizeX      == theViewportSizeX
+   && myVPSizeY      == theViewportSizeY
+   && myColorFormats == theColorFormats
+   && myDepthFormat  == theDepthFormat
+   && myNbSamples    == theNbSamples)
   {
-    // application can not handle this case by exception - this is bug in code
-    Standard_ASSERT_RETURN (theGlCtx != NULL,
-      "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
+    return IsValid();
   }
-  if (isValidStencilBuffer())
+
+  return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormats, theDepthFormat, theNbSamples);
+}
+
+// =======================================================================
+// function : InitWithRB
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
+                                                 const GLsizei                 theSizeX,
+                                                 const GLsizei                 theSizeY,
+                                                 const GLint                   theColorFormat,
+                                                 const GLint                   theDepthFormat,
+                                                 const GLuint                  theColorRBufferFromWindow)
+{
+  myColorFormats.Clear();
+  myColorFormats.Append (theColorFormat);
+  if (!myColorTextures.IsEmpty())
   {
-    if (theGlCtx->IsValid()
-     && myGlStencilRBId != myGlDepthRBId)
+    Handle(OpenGl_Texture) aTexutre = myColorTextures.First();
+    for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
     {
-      theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlStencilRBId);
+      aTextureIt.Value()->Release (theGlCtx.operator->());
     }
-    myGlStencilRBId = NO_RENDERBUFFER;
+    myColorTextures.Clear();
+    myColorTextures.Append (aTexutre);
   }
-  if (isValidDepthBuffer())
+
+  myDepthFormat = theDepthFormat;
+  myNbSamples   = 0;
+  myInitVPSizeX = theSizeX;
+  myInitVPSizeY = theSizeY;
+  if (theGlCtx->arbFBO == NULL)
   {
-    if (theGlCtx->IsValid())
-    {
-      theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlDepthRBId);
-    }
-    myGlDepthRBId = NO_RENDERBUFFER;
+    return Standard_False;
+  }
+
+  // clean up previous state
+  Release (theGlCtx.operator->());
+
+  myIsOwnBuffer = true;
+  myIsOwnDepth  = true;
+
+  // setup viewport sizes as is
+  myVPSizeX = theSizeX;
+  myVPSizeY = theSizeY;
+  const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
+  const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
+
+  // Create the render-buffers
+  if (theColorRBufferFromWindow != NO_RENDERBUFFER)
+  {
+    myGlColorRBufferId = theColorRBufferFromWindow;
   }
-  if (isValidTexture())
+  else if (theColorFormat != 0)
   {
-    if (theGlCtx->IsValid())
-    {
-      glDeleteTextures (1, &myGlTextureId);
-    }
-    myGlTextureId = NO_TEXTURE;
+    theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
+    theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
+    theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, theColorFormat, aSizeX, aSizeY);
   }
-  mySizeX = mySizeY = myVPSizeX = myVPSizeY = 0;
-  if (isValidFrameBuffer())
+
+  bool hasStencilRB = false;
+  if (myDepthFormat != 0)
   {
-    if (theGlCtx->IsValid())
+    GLenum aPixelFormat = 0;
+    GLenum aDataType    = 0;
+    getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType);
+    hasStencilRB = aPixelFormat == GL_DEPTH_STENCIL;
+
+    theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
+    theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
+    theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
+    theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+  }
+
+  // create FBO
+  theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
+  theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
+  theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                               GL_RENDERBUFFER, myGlColorRBufferId);
+  if (myGlDepthRBufferId != NO_RENDERBUFFER)
+  {
+  #ifdef GL_DEPTH_STENCIL_ATTACHMENT
+    theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
+                                                 GL_RENDERBUFFER, myGlDepthRBufferId);
+  #else
+    theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                                 GL_RENDERBUFFER, myGlDepthRBufferId);
+    if (hasStencilRB)
     {
-      theGlCtx->extFBO->glDeleteFramebuffersEXT (1, &myGlFBufferId);
+      theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                                   GL_RENDERBUFFER, myGlDepthRBufferId);
     }
-    myGlFBufferId = NO_FRAMEBUFFER;
+  #endif
   }
+  if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+  {
+    UnbindBuffer (theGlCtx);
+    Release (theGlCtx.operator->());
+    return Standard_False;
+  }
+
+  UnbindBuffer (theGlCtx);
+  return Standard_True;
 }
 
 // =======================================================================
-// function : isProxySuccess
+// function : InitWrapper
 // purpose  :
 // =======================================================================
-Standard_Boolean OpenGl_FrameBuffer::isProxySuccess() const
+Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
 {
-  // use proxy to check texture could be created or not
-  glTexImage2D (GL_PROXY_TEXTURE_2D,
-                0,                // LOD number: 0 - base image level; n is the nth mipmap reduction image
-                myTextFormat,     // internalformat
-                mySizeX, mySizeY, 0,
-                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-  GLint aTestParamX (0), aTestParamY (0);
-  glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamX);
-  glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamY);
-  return aTestParamX != 0 && aTestParamY != 0;
+  myNbSamples = 0;
+  if (theGlCtx->arbFBO == NULL)
+  {
+    return Standard_False;
+  }
+
+  // clean up previous state
+  Release (theGlCtx.operator->());
+
+  GLint anFbo = GLint(NO_FRAMEBUFFER);
+  ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
+  if (anFbo == GLint(NO_FRAMEBUFFER))
+  {
+    return Standard_False;
+  }
+
+  GLint aColorType = 0;
+  GLint aColorId   = 0;
+  GLint aDepthType = 0;
+  GLint aDepthId   = 0;
+  theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
+  theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
+
+  myGlFBufferId = GLuint(anFbo);
+  myIsOwnBuffer = false;
+  myIsOwnDepth  = false;
+  if (aColorType == GL_RENDERBUFFER)
+  {
+    theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
+    myGlColorRBufferId = aColorId;
+  }
+  else if (aColorType != GL_NONE)
+  {
+    TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
+    theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
+                           GL_DEBUG_TYPE_ERROR,
+                           0,
+                           GL_DEBUG_SEVERITY_HIGH,
+                           aMsg);
+  }
+
+  if (aDepthType == GL_RENDERBUFFER)
+  {
+    theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
+    myGlDepthRBufferId = aDepthId;
+  }
+  else if (aDepthType != GL_NONE)
+  {
+    TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
+    theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
+                           GL_DEBUG_TYPE_ERROR,
+                           0,
+                           GL_DEBUG_SEVERITY_HIGH,
+                           aMsg);
+  }
+
+  // retrieve dimensions
+  GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
+  if (aRBuffer != NO_RENDERBUFFER)
+  {
+    theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
+    theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH,  &myVPSizeX);
+    theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
+    theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+  }
+
+  return aRBuffer != NO_RENDERBUFFER;
 }
 
 // =======================================================================
-// function : initTrashTexture
+// function : Release
 // purpose  :
 // =======================================================================
-Standard_Boolean OpenGl_FrameBuffer::initTrashTexture (const Handle(OpenGl_Context)& theGlContext)
+void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
 {
-  // Check texture size is fit dimension maximum
-  GLint aMaxTexDim = 2048;
-  glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aMaxTexDim);
-  if (mySizeX > aMaxTexDim || mySizeY > aMaxTexDim)
+  if (isValidFrameBuffer())
   {
-    return Standard_False;
+    // application can not handle this case by exception - this is bug in code
+    Standard_ASSERT_RETURN (theGlCtx != NULL,
+      "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
+    if (theGlCtx->IsValid()
+     && myIsOwnBuffer)
+    {
+      theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
+      if (myGlColorRBufferId != NO_RENDERBUFFER)
+      {
+        theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
+      }
+      if (myGlDepthRBufferId != NO_RENDERBUFFER)
+      {
+        theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
+      }
+    }
+    myGlFBufferId      = NO_FRAMEBUFFER;
+    myGlColorRBufferId = NO_RENDERBUFFER;
+    myGlDepthRBufferId = NO_RENDERBUFFER;
+    myIsOwnBuffer      = false;
   }
 
-  // generate new id
-  glEnable (GL_TEXTURE_2D);
-  if (!isValidTexture())
+  for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
   {
-    glGenTextures (1, &myGlTextureId); // Create The Texture
+    myColorTextures (aColorBufferIdx)->Release (theGlCtx);
   }
-  glBindTexture (GL_TEXTURE_2D, myGlTextureId);
-
-  // texture interpolation parameters - could be overridden later
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 
-  if (!isProxySuccess())
+  if (myIsOwnDepth)
   {
-    Release (theGlContext.operator->());
-    return Standard_False;
+    myDepthStencilTexture->Release (theGlCtx);
+    myIsOwnDepth = false;
   }
 
-  glTexImage2D (GL_TEXTURE_2D,
-                0,                // LOD number: 0 - base image level; n is the nth mipmap reduction image
-                myTextFormat,     // internalformat
-                mySizeX, mySizeY, 0,
-                GL_RGBA, GL_UNSIGNED_BYTE, NULL); // NULL pointer supported from OpenGL 1.1
-  return Standard_True;
+  myVPSizeX = 0;
+  myVPSizeY = 0;
 }
 
 // =======================================================================
 // function : SetupViewport
 // purpose  :
 // =======================================================================
-void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/)
+void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& theGlCtx)
 {
-  glViewport (0, 0, myVPSizeX, myVPSizeY);
+  const Standard_Integer aViewport[4] = { 0, 0, myVPSizeX, myVPSizeY };
+  theGlCtx->ResizeViewport (aViewport);
 }
 
 // =======================================================================
@@ -286,7 +788,25 @@ void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
 // =======================================================================
 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
 {
-  theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
+  theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
+}
+
+// =======================================================================
+// function : BindDrawBuffer
+// purpose  :
+// =======================================================================
+void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
+{
+  theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
+}
+
+// =======================================================================
+// function : BindReadBuffer
+// purpose  :
+// =======================================================================
+void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
+{
+  theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
 }
 
 // =======================================================================
@@ -295,25 +815,282 @@ void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
 // =======================================================================
 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
 {
-  theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, NO_FRAMEBUFFER);
+  if (!theGlCtx->DefaultFrameBuffer().IsNull()
+   &&  theGlCtx->DefaultFrameBuffer().operator->() != this)
+  {
+    theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
+  }
+  else
+  {
+    theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
+  }
 }
 
 // =======================================================================
-// function : BindTexture
+// function : getAligned
 // purpose  :
 // =======================================================================
-void OpenGl_FrameBuffer::BindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/)
+inline Standard_Size getAligned (const Standard_Size theNumber,
+                                 const Standard_Size theAlignment)
 {
-  glEnable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering
-  glBindTexture (GL_TEXTURE_2D, myGlTextureId);
+  return theNumber + theAlignment - 1 - (theNumber - 1) % theAlignment;
+}
+
+template<typename T>
+inline void convertRowFromRgba (T* theRgbRow,
+                                const Image_ColorRGBA* theRgbaRow,
+                                const Standard_Size theWidth)
+{
+  for (Standard_Size aCol = 0; aCol < theWidth; ++aCol)
+  {
+    const Image_ColorRGBA& anRgba = theRgbaRow[aCol];
+    T& anRgb = theRgbRow[aCol];
+    anRgb.r() = anRgba.r();
+    anRgb.g() = anRgba.g();
+    anRgb.b() = anRgba.b();
+  }
 }
 
 // =======================================================================
-// function : UnbindTexture
+// function : BufferDump
 // purpose  :
 // =======================================================================
-void OpenGl_FrameBuffer::UnbindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/)
+Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& theGlCtx,
+                                                 const Handle(OpenGl_FrameBuffer)& theFbo,
+                                                 Image_PixMap& theImage,
+                                                 Graphic3d_BufferType theBufferType)
 {
-  glBindTexture (GL_TEXTURE_2D, NO_TEXTURE);
-  glDisable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering
+  if (theGlCtx.IsNull()
+   || theImage.IsEmpty())
+  {
+    return Standard_False;
+  }
+
+  GLenum aFormat = 0;
+  GLenum aType   = 0;
+  bool toSwapRgbaBgra = false;
+  bool toConvRgba2Rgb = false;
+  switch (theImage.Format())
+  {
+  #if !defined(GL_ES_VERSION_2_0)
+    case Image_Format_Gray:
+      aFormat = GL_DEPTH_COMPONENT;
+      aType   = GL_UNSIGNED_BYTE;
+      break;
+    case Image_Format_GrayF:
+      aFormat = GL_DEPTH_COMPONENT;
+      aType   = GL_FLOAT;
+      break;
+    case Image_Format_RGB:
+      aFormat = GL_RGB;
+      aType   = GL_UNSIGNED_BYTE;
+      break;
+    case Image_Format_BGR:
+      aFormat = GL_BGR;
+      aType   = GL_UNSIGNED_BYTE;
+      break;
+    case Image_Format_BGRA:
+    case Image_Format_BGR32:
+      aFormat = GL_BGRA;
+      aType   = GL_UNSIGNED_BYTE;
+      break;
+    case Image_Format_BGRF:
+      aFormat = GL_BGR;
+      aType   = GL_FLOAT;
+      break;
+    case Image_Format_BGRAF:
+      aFormat = GL_BGRA;
+      aType   = GL_FLOAT;
+      break;
+  #else
+    case Image_Format_Gray:
+    case Image_Format_GrayF:
+    case Image_Format_BGRF:
+    case Image_Format_BGRAF:
+      return Standard_False;
+    case Image_Format_BGRA:
+    case Image_Format_BGR32:
+      aFormat = GL_RGBA;
+      aType   = GL_UNSIGNED_BYTE;
+      toSwapRgbaBgra = true;
+      break;
+    case Image_Format_BGR:
+    case Image_Format_RGB:
+      aFormat = GL_RGBA;
+      aType   = GL_UNSIGNED_BYTE;
+      toConvRgba2Rgb = true;
+      break;
+  #endif
+    case Image_Format_RGBA:
+    case Image_Format_RGB32:
+      aFormat = GL_RGBA;
+      aType   = GL_UNSIGNED_BYTE;
+      break;
+    case Image_Format_RGBF:
+      aFormat = GL_RGB;
+      aType   = GL_FLOAT;
+      break;
+    case Image_Format_RGBAF:
+      aFormat = GL_RGBA;
+      aType   = GL_FLOAT;
+      break;
+    case Image_Format_Alpha:
+    case Image_Format_AlphaF:
+      return Standard_False; // GL_ALPHA is no more supported in core context
+    case Image_Format_UNKNOWN:
+      return Standard_False;
+  }
+
+  if (aFormat == 0)
+  {
+    return Standard_False;
+  }
+
+#if !defined(GL_ES_VERSION_2_0)
+  GLint aReadBufferPrev = GL_BACK;
+  if (theBufferType == Graphic3d_BT_Depth
+   && aFormat != GL_DEPTH_COMPONENT)
+  {
+    return Standard_False;
+  }
+#else
+  (void )theBufferType;
+#endif
+
+  // bind FBO if used
+  if (!theFbo.IsNull() && theFbo->IsValid())
+  {
+    theFbo->BindBuffer (theGlCtx);
+  }
+  else
+  {
+  #if !defined(GL_ES_VERSION_2_0)
+    glGetIntegerv (GL_READ_BUFFER, &aReadBufferPrev);
+    GLint aDrawBufferPrev = GL_BACK;
+    glGetIntegerv (GL_DRAW_BUFFER, &aDrawBufferPrev);
+    glReadBuffer (aDrawBufferPrev);
+  #endif
+  }
+
+  // setup alignment
+  const GLint anAligment   = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
+  glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
+  bool isBatchCopy = !theImage.IsTopDown();
+
+  const GLint   anExtraBytes       = GLint(theImage.RowExtraBytes());
+  GLint         aPixelsWidth       = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
+  Standard_Size aSizeRowBytesEstim = getAligned (theImage.SizePixelBytes() * aPixelsWidth, anAligment);
+  if (anExtraBytes < anAligment)
+  {
+    aPixelsWidth = 0;
+  }
+  else if (aSizeRowBytesEstim != theImage.SizeRowBytes())
+  {
+    aPixelsWidth = 0;
+    isBatchCopy  = false;
+  }
+#if !defined(GL_ES_VERSION_2_0)
+  glPixelStorei (GL_PACK_ROW_LENGTH, aPixelsWidth);
+#else
+  if (aPixelsWidth != 0)
+  {
+    isBatchCopy = false;
+  }
+#endif
+  if (toConvRgba2Rgb)
+  {
+    Handle(NCollection_BaseAllocator) anAlloc = new NCollection_AlignedAllocator (16);
+    const Standard_Size aRowSize = theImage.SizeX() * 4;
+    NCollection_Buffer aRowBuffer (anAlloc);
+    if (!aRowBuffer.Allocate (aRowSize))
+    {
+      return Standard_False;
+    }
+
+    for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
+    {
+      // Image_PixMap rows indexation always starts from the upper corner
+      // while order in memory depends on the flag and processed by ChangeRow() method
+      glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, aRowBuffer.ChangeData());
+      const Image_ColorRGBA* aRowDataRgba = (const Image_ColorRGBA* )aRowBuffer.Data();
+      if (theImage.Format() == Image_Format_BGR)
+      {
+        convertRowFromRgba ((Image_ColorBGR* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
+      }
+      else
+      {
+        convertRowFromRgba ((Image_ColorRGB* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
+      }
+    }
+  }
+  else if (!isBatchCopy)
+  {
+    // copy row by row
+    for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
+    {
+      // Image_PixMap rows indexation always starts from the upper corner
+      // while order in memory depends on the flag and processed by ChangeRow() method
+      glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, theImage.ChangeRow (aRow));
+    }
+  }
+  else
+  {
+    glReadPixels (0, 0, GLsizei (theImage.SizeX()), GLsizei (theImage.SizeY()), aFormat, aType, theImage.ChangeData());
+  }
+  const bool hasErrors = theGlCtx->ResetErrors (true);
+
+  glPixelStorei (GL_PACK_ALIGNMENT,  1);
+#if !defined(GL_ES_VERSION_2_0)
+  glPixelStorei (GL_PACK_ROW_LENGTH, 0);
+#endif
+
+  if (!theFbo.IsNull() && theFbo->IsValid())
+  {
+    theFbo->UnbindBuffer (theGlCtx);
+  }
+  else
+  {
+  #if !defined(GL_ES_VERSION_2_0)
+    glReadBuffer (aReadBufferPrev);
+  #endif
+  }
+
+  if (toSwapRgbaBgra)
+  {
+    Image_PixMap::SwapRgbaBgra (theImage);
+  }
+
+  return !hasErrors;
+}
+
+// =======================================================================
+// 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;
 }