0026711: Visualization, TKOpenGl - support creation of multisampling off-screen FBOs
authorkgv <kgv@opencascade.com>
Wed, 21 Oct 2015 16:06:02 +0000 (19:06 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 29 Oct 2015 10:28:11 +0000 (13:28 +0300)
OpenGl_Texture::Init2DMultisample() - new method to initialize multisampled texture.
Graphic3d_RenderingParams::NbMsaaSamples - add option defining MSAA samples number.

RayTracing will keep using FBO without MSAA, however it is possible to combine
MSAA for rasterization and FSAA for RayTracing.

OpenGl_FrameBuffer constructor has been changed to do not take arguments.
OpenGl_FrameBuffer::Init() method has been extended with mandatory parameters
defining Color and Depth attachment formats
and optional parameter defining number of MSAA parameters.

Draw Harness, add option -msaa to vrenderparams.

17 files changed:
src/Graphic3d/Graphic3d_RenderingParams.hxx
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_FrameBuffer.cxx
src/OpenGl/OpenGl_FrameBuffer.hxx
src/OpenGl/OpenGl_GlFunctions.hxx
src/OpenGl/OpenGl_Texture.cxx
src/OpenGl/OpenGl_Texture.hxx
src/OpenGl/OpenGl_View.cxx
src/OpenGl/OpenGl_View.hxx
src/OpenGl/OpenGl_View_Print.cxx
src/OpenGl/OpenGl_View_Raytrace.cxx
src/OpenGl/OpenGl_View_Redraw.cxx
src/OpenGl/OpenGl_Window_1.mm
src/OpenGl/OpenGl_Workspace.cxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/v3d/glsl/msaa [new file with mode: 0644]

index b574213..c933090 100644 (file)
@@ -50,6 +50,8 @@ public:
   //! Creates default rendering parameters.
   Graphic3d_RenderingParams()
   : Method                      (Graphic3d_RM_RASTERIZATION),
+    NbMsaaSamples               (0),
+    // ray tracing parameters
     IsGlobalIlluminationEnabled (Standard_False),
     SamplesPerPixel             (THE_DEFAULT_SPP),
     RaytracingDepth             (THE_DEFAULT_DEPTH),
@@ -59,7 +61,7 @@ public:
     IsTransparentShadowEnabled  (Standard_False),
     UseEnvironmentMapBackground (Standard_False),
     CoherentPathTracingMode     (Standard_False),
-
+    // stereoscopic parameters
     StereoMode (Graphic3d_StereoMode_QuadBuffer),
     AnaglyphFilter (Anaglyph_RedCyan_Optimized),
     ToReverseStereo (Standard_False),
@@ -80,6 +82,7 @@ public:
 public:
 
   Graphic3d_RenderingMode Method;                      //!< specifies rendering mode, Graphic3d_RM_RASTERIZATION by default
+  Standard_Integer        NbMsaaSamples;               //!< number of MSAA samples (should be within 0..GL_MAX_SAMPLES, power-of-two number), 0 by default
 
   Standard_Boolean        IsGlobalIlluminationEnabled; //!< enables/disables global illumination effects (path tracing)
   Standard_Integer        SamplesPerPixel;             //!< number of samples per pixel (SPP)
index 2a960a2..52b4f22 100644 (file)
@@ -126,6 +126,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myTexClamp   (GL_CLAMP_TO_EDGE),
   myMaxTexDim  (1024),
   myMaxClipPlanes (6),
+  myMaxMsaaSamples(0),
   myGlVerMajor (0),
   myGlVerMinor (0),
   myIsInitialized (Standard_False),
@@ -275,33 +276,6 @@ void OpenGl_Context::forcedRelease()
   }
 }
 
-// =======================================================================
-// function : MaxDegreeOfAnisotropy
-// purpose  :
-// =======================================================================
-Standard_Integer OpenGl_Context::MaxDegreeOfAnisotropy() const
-{
-  return myAnisoMax;
-}
-
-// =======================================================================
-// function : MaxTextureSize
-// purpose  :
-// =======================================================================
-Standard_Integer OpenGl_Context::MaxTextureSize() const
-{
-  return myMaxTexDim;
-}
-
-// =======================================================================
-// function : MaxClipPlanes
-// purpose  :
-// =======================================================================
-Standard_Integer OpenGl_Context::MaxClipPlanes() const
-{
-  return myMaxClipPlanes;
-}
-
 #if !defined(GL_ES_VERSION_2_0)
 inline Standard_Integer stereoToMonoBuffer (const Standard_Integer theBuffer)
 {
@@ -763,11 +737,42 @@ Standard_Boolean OpenGl_Context::Init (const Aspect_Drawable         theWindow,
 // function : ResetErrors
 // purpose  :
 // =======================================================================
-void OpenGl_Context::ResetErrors()
+void OpenGl_Context::ResetErrors (const bool theToPrintErrors)
 {
-  while (glGetError() != GL_NO_ERROR)
+  int aPrevErr = 0;
+  int anErr    = ::glGetError();
+  if (!theToPrintErrors)
   {
-    //
+    for (; anErr != GL_NO_ERROR && aPrevErr != anErr; aPrevErr = anErr, anErr = ::glGetError())
+    {
+      //
+    }
+    return;
+  }
+
+  for (; anErr != GL_NO_ERROR && aPrevErr != anErr; aPrevErr = anErr, anErr = ::glGetError())
+  {
+    TCollection_ExtendedString anErrId;
+    switch (anErr)
+    {
+      case GL_INVALID_ENUM:      anErrId = "GL_INVALID_ENUM";      break;
+      case GL_INVALID_VALUE:     anErrId = "GL_INVALID_VALUE";     break;
+      case GL_INVALID_OPERATION: anErrId = "GL_INVALID_OPERATION"; break;
+    #ifdef GL_STACK_OVERFLOW
+      case GL_STACK_OVERFLOW:    anErrId = "GL_STACK_OVERFLOW";    break;
+      case GL_STACK_UNDERFLOW:   anErrId = "GL_STACK_UNDERFLOW";   break;
+    #endif
+      case GL_OUT_OF_MEMORY:     anErrId = "GL_OUT_OF_MEMORY";     break;
+      case GL_INVALID_FRAMEBUFFER_OPERATION:
+        anErrId = "GL_INVALID_FRAMEBUFFER_OPERATION";
+        break;
+      default:
+        anErrId = TCollection_ExtendedString("#") + anErr;
+        break;
+    }
+
+    const TCollection_ExtendedString aMsg = TCollection_ExtendedString ("Unhandled GL error: ") + anErrId;
+    PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
   }
 }
 
@@ -1015,6 +1020,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   // read version
   myGlVerMajor = 0;
   myGlVerMinor = 0;
+  myMaxMsaaSamples = 0;
   ReadGlVersion (myGlVerMajor, myGlVerMinor);
   myVendor = (const char* )::glGetString (GL_VENDOR);
 
@@ -1111,6 +1117,13 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   {
     arbFBOBlit = (OpenGl_ArbFBOBlit* )(&(*myFuncs));
   }
+  if (IsGlGreaterEqual (3, 1)
+   && FindProc ("glTexStorage2DMultisample", myFuncs->glTexStorage2DMultisample))
+  {
+    // MSAA RenderBuffers have been defined in OpenGL ES 3.0,
+    // but MSAA Textures - only in OpenGL ES 3.1+
+    ::glGetIntegerv (GL_MAX_SAMPLES, &myMaxMsaaSamples);
+  }
 
   hasUintIndex = IsGlGreaterEqual (3, 0)
               || CheckExtension ("GL_OES_element_index_uint");
@@ -2115,6 +2128,24 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     return;
   }
 
+  // MSAA RenderBuffers have been defined in OpenGL 3.0,
+  // but MSAA Textures - only in OpenGL 3.2+
+  if (!has32
+   && CheckExtension ("GL_ARB_texture_multisample")
+   && FindProcShort (glTexImage2DMultisample))
+  {
+    GLint aNbColorSamples = 0, aNbDepthSamples = 0;
+    ::glGetIntegerv (GL_MAX_COLOR_TEXTURE_SAMPLES, &aNbColorSamples);
+    ::glGetIntegerv (GL_MAX_DEPTH_TEXTURE_SAMPLES, &aNbDepthSamples);
+    myMaxMsaaSamples = Min (aNbColorSamples, aNbDepthSamples);
+  }
+  if (!has43
+   && CheckExtension ("GL_ARB_texture_storage_multisample")
+   && FindProcShort (glTexStorage2DMultisample))
+  {
+    //
+  }
+
   if (!has31)
   {
     checkWrongVersion (3, 1);
@@ -2141,6 +2172,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   {
     core32back = (OpenGl_GlCore32Back* )(&(*myFuncs));
   }
+  ::glGetIntegerv (GL_MAX_SAMPLES, &myMaxMsaaSamples);
 
   if (!has33)
   {
index 074f467..163265d 100644 (file)
@@ -308,7 +308,7 @@ public:
   const OpenGl_GlFunctions* Functions() const { return myFuncs.operator->(); }
 
   //! Clean up errors stack for this GL context (glGetError() in loop).
-  Standard_EXPORT void ResetErrors();
+  Standard_EXPORT void ResetErrors (const bool theToPrintErrors = false);
 
   //! This method uses system-dependent API to retrieve information
   //! about GL context bound to the current thread.
@@ -421,16 +421,19 @@ public:
   Standard_Integer TextureWrapClamp() const { return myTexClamp; }
 
   //! @return maximum degree of anisotropy texture filter
-  Standard_EXPORT Standard_Integer MaxDegreeOfAnisotropy() const;
+  Standard_Integer MaxDegreeOfAnisotropy() const { return myAnisoMax; }
 
   //! @return value for GL_MAX_TEXTURE_SIZE
-  Standard_EXPORT Standard_Integer MaxTextureSize() const;
+  Standard_Integer MaxTextureSize() const { return myMaxTexDim; }
+
+  //! @return value for GL_MAX_SAMPLES
+  Standard_Integer MaxMsaaSamples() const { return myMaxMsaaSamples; }
 
   //! Get maximum number of clip planes supported by OpenGl.
   //! This value is implementation dependent. At least 6
   //! planes should be supported by OpenGl (see specs).
   //! @return value for GL_MAX_CLIP_PLANES
-  Standard_EXPORT Standard_Integer MaxClipPlanes() const;
+  Standard_Integer MaxClipPlanes() const { return myMaxClipPlanes; }
 
   //! Returns true if VBO is supported and permitted.
   inline bool ToUseVbo() const
@@ -680,6 +683,7 @@ private: // context info
   Standard_Integer myTexClamp;             //!< either GL_CLAMP_TO_EDGE (1.2+) or GL_CLAMP (1.1)
   Standard_Integer myMaxTexDim;            //!< value for GL_MAX_TEXTURE_SIZE
   Standard_Integer myMaxClipPlanes;        //!< value for GL_MAX_CLIP_PLANES
+  Standard_Integer myMaxMsaaSamples;       //!< value for GL_MAX_SAMPLES
   Standard_Integer myGlVerMajor;           //!< cached GL version major number
   Standard_Integer myGlVerMinor;           //!< cached GL version minor number
   Standard_Boolean myIsInitialized;        //!< flag indicates initialization state
index 38cb43f..caf82a2 100644 (file)
 #include <Standard_Assert.hxx>
 #include <TCollection_ExtendedString.hxx>
 
+namespace
+{
+
+  //! Determine data type from texture sized format.
+  static bool getDepthDataFormat (GLint   theTextFormat,
+                                  GLenum& thePixelFormat,
+                                  GLenum& theDataType)
+  {
+    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;
+        theDataType    = GL_UNSIGNED_SHORT;
+        return true;
+      }
+      case GL_DEPTH_COMPONENT24:
+      {
+        thePixelFormat = GL_DEPTH;
+        theDataType    = GL_UNSIGNED_INT;
+        return true;
+      }
+      case GL_DEPTH_COMPONENT32F:
+      {
+        thePixelFormat = GL_DEPTH;
+        theDataType    = GL_FLOAT;
+        return true;
+      }
+    }
+    return false;
+  }
+
+}
 
 // =======================================================================
 // function : OpenGl_FrameBuffer
 // purpose  :
 // =======================================================================
-OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
+OpenGl_FrameBuffer::OpenGl_FrameBuffer()
 : myVPSizeX (0),
   myVPSizeY (0),
-  myTextFormat (theTextureFormat),
+  myNbSamples (0),
+  myColorFormat (GL_RGBA8),
+  myDepthFormat (GL_DEPTH24_STENCIL8),
   myGlFBufferId (NO_FRAMEBUFFER),
   myGlColorRBufferId (NO_RENDERBUFFER),
   myGlDepthRBufferId (NO_RENDERBUFFER),
@@ -52,8 +99,14 @@ OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
 // =======================================================================
 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
                                            const GLsizei   theSizeX,
-                                           const GLsizei   theSizeY)
+                                           const GLsizei   theSizeY,
+                                           const GLint     theColorFormat,
+                                           const GLint     theDepthFormat,
+                                           const GLsizei   theNbSamples)
 {
+  myColorFormat = theColorFormat;
+  myDepthFormat = theDepthFormat;
+  myNbSamples   = theNbSamples;
   if (theGlContext->arbFBO == NULL)
   {
     return Standard_False;
@@ -61,6 +114,11 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
 
   // clean up previous state
   Release (theGlContext.operator->());
+  if (myColorFormat == 0
+   && myDepthFormat == 0)
+  {
+    return Standard_False;
+  }
 
   myIsOwnBuffer = true;
 
@@ -71,49 +129,75 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
   const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
 
   // Create the textures (will be used as color buffer and depth-stencil buffer)
-  if (!myColorTexture->Init (theGlContext, myTextFormat,
-                             GL_RGBA, GL_UNSIGNED_BYTE,
-                             aSizeX, aSizeY, Graphic3d_TOT_2D))
+  if (theNbSamples != 0)
   {
-    Release (theGlContext.operator->());
-    return Standard_False;
+    if (myColorFormat != 0
+    && !myColorTexture       ->Init2DMultisample (theGlContext, theNbSamples, myColorFormat, aSizeX, aSizeY))
+    {
+      Release (theGlContext.operator->());
+      return Standard_False;
+    }
+    if (myDepthFormat != 0
+    && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
+    {
+      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 (!myDepthStencilTexture->Init (theGlContext, GL_DEPTH24_STENCIL8,
-                                    GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8,
-                                    aSizeX, aSizeY, Graphic3d_TOT_2D))
+  else
   {
-    TCollection_ExtendedString aMsg = TCollection_ExtendedString()
-      + "Warning! Depth textures are not supported by hardware!";
-    theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-                               GL_DEBUG_TYPE_PORTABILITY_ARB,
-                               0,
-                               GL_DEBUG_SEVERITY_HIGH_ARB,
-                               aMsg);
-
-    theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
-    theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
-    theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, aSizeX, aSizeY);
-    theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+    if (myColorFormat != 0
+    && !myColorTexture->Init (theGlContext, myColorFormat,
+                              GL_RGBA, GL_UNSIGNED_BYTE,
+                              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
+    GLenum aPixelFormat = 0;
+    GLenum aDataType    = 0;
+    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_ARB,
+                                 GL_DEBUG_TYPE_PORTABILITY_ARB,
+                                 0,
+                                 GL_DEBUG_SEVERITY_HIGH_ARB,
+                                 aMsg);
+
+      theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
+      theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
+      theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, aSizeX, aSizeY);
+      theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+    }
   }
 
   // Build FBO and setup it as texture
   theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
   theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
-  theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                                GL_TEXTURE_2D, myColorTexture->TextureId(), 0);
+  if (myColorTexture->IsValid())
+  {
+    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                                  myColorTexture->GetTarget(), myColorTexture->TextureId(), 0);
+  }
   if (myDepthStencilTexture->IsValid())
   {
   #ifdef GL_DEPTH_STENCIL_ATTACHMENT
     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
-                                                  GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
   #else
     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                                  GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-                                                  GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
   #endif
   }
   else if (myGlDepthRBufferId != NO_RENDERBUFFER)
@@ -137,16 +221,21 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
 // =======================================================================
 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
                                                const GLsizei                 theViewportSizeX,
-                                               const GLsizei                 theViewportSizeY)
+                                               const GLsizei                 theViewportSizeY,
+                                               const GLint                   theColorFormat,
+                                               const GLint                   theDepthFormat,
+                                               const GLsizei                 theNbSamples)
 {
-  if (myVPSizeX == theViewportSizeX
-   && myVPSizeY == theViewportSizeY)
-
+  if (myVPSizeX     == theViewportSizeX
+   && myVPSizeY     == theViewportSizeY
+   && myColorFormat == theColorFormat
+   && myDepthFormat == theDepthFormat
+   && myNbSamples   == theNbSamples)
   {
     return IsValid();
   }
 
-  return Init (theGlContext, theViewportSizeX, theViewportSizeY);
+  return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormat, theDepthFormat, theNbSamples);
 }
 
 // =======================================================================
@@ -156,8 +245,13 @@ Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& the
 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)
 {
+  myColorFormat = theColorFormat;
+  myDepthFormat = theDepthFormat;
+  myNbSamples   = 0;
   if (theGlCtx->arbFBO == NULL)
   {
     return Standard_False;
@@ -179,33 +273,38 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
   {
     myGlColorRBufferId = theColorRBufferFromWindow;
   }
-  else
+  else if (myColorFormat != 0)
   {
     theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
-    theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA8, aSizeX, aSizeY);
+    theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myColorFormat, aSizeX, aSizeY);
   }
 
-  theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
-  theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
-  theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, aSizeX, aSizeY);
-
-  theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+  if (myDepthFormat != 0)
+  {
+    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);
-#ifdef GL_DEPTH_STENCIL_ATTACHMENT
-  theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
-                                               GL_RENDERBUFFER, myGlDepthRBufferId);
-#else
-  theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                               GL_RENDERBUFFER, myGlDepthRBufferId);
-  theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-                                               GL_RENDERBUFFER, myGlDepthRBufferId);
-#endif
+  if (myGlDepthRBufferId != NO_RENDERBUFFER)
+  {
+  #ifdef GL_DEPTH_STENCIL_ATTACHMENT
+    theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                                                 GL_RENDERBUFFER, myGlDepthRBufferId);
+  #else
+    theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                                 GL_RENDERBUFFER, myGlDepthRBufferId);
+    theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                                 GL_RENDERBUFFER, myGlDepthRBufferId);
+  #endif
+  }
   if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
   {
     UnbindBuffer (theGlCtx);
@@ -223,6 +322,7 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
 // =======================================================================
 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
 {
+  myNbSamples = 0;
   if (theGlCtx->arbFBO == NULL)
   {
     return Standard_False;
index 0fceeaf..6c907b0 100644 (file)
@@ -39,7 +39,7 @@ public:
 public:
 
   //! Empty constructor
-  Standard_EXPORT OpenGl_FrameBuffer (GLint theTextureFormat = GL_RGBA8);
+  Standard_EXPORT OpenGl_FrameBuffer();
 
   //! Destructor
   Standard_EXPORT virtual ~OpenGl_FrameBuffer();
@@ -47,6 +47,24 @@ public:
   //! Destroy object - will release GPU memory if any.
   Standard_EXPORT virtual void Release (OpenGl_Context* theGlCtx);
 
+  //! Number of multisampling samples.
+  GLsizei NbSamples() const
+  {
+    return myNbSamples;
+  }
+
+  //! Return true if FBO has been created with color attachment.
+  bool HasColor() const
+  {
+    return myColorFormat != 0;
+  }
+
+  //! Return true if FBO has been created with depth attachment.
+  bool HasDepth() const
+  {
+    return myDepthFormat != 0;
+  }
+
   //! Textures width.
   GLsizei GetSizeX() const
   {
@@ -77,32 +95,49 @@ public:
     return isValidFrameBuffer();
   }
 
-  //! Notice! Obsolete hardware (GeForce FX etc)
-  //! doesn't support rectangular textures!
-  //! There are 3 possible results if you are trying
-  //! to create non power-of-two FBO on these cards:
-  //! 1) FBO creation will fail,
-  //!    current implementation will try to generate compatible FBO;
-  //! 2) FBO rendering will be done in software mode (ForceWare 'hack');
-  //! 3) FBO rendering will be incorrect (some obsolete Catalyst drivers).
+  //! Initialize FBO for rendering into textures.
+  //! @param theGlCtx       currently bound OpenGL context
+  //! @param theSizeX       texture width
+  //! @param theSizeY       texture height
+  //! @param theColorFormat color         texture sized format (0 means no color attachment), e.g. GL_RGBA8
+  //! @param theDepthFormat depth-stencil texture sized format (0 means no depth attachment), e.g. GL_DEPTH24_STENCIL8
+  //! @param theNbSamples   MSAA number of samples (0 means normal texture)
+  //! @return true on success
   Standard_EXPORT Standard_Boolean Init (const Handle(OpenGl_Context)& theGlCtx,
-                                         const GLsizei                 theViewportSizeX,
-                                         const GLsizei                 theViewportSizeY);
+                                         const GLsizei                 theSizeX,
+                                         const GLsizei                 theSizeY,
+                                         const GLint                   theColorFormat,
+                                         const GLint                   theDepthFormat,
+                                         const GLsizei                 theNbSamples = 0);
 
   //! (Re-)initialize FBO with specified dimensions.
   Standard_EXPORT Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx,
                                              const GLsizei                 theViewportSizeX,
-                                             const GLsizei                 theViewportSizeY);
+                                             const GLsizei                 theViewportSizeY,
+                                             const GLint                   theColorFormat,
+                                             const GLint                   theDepthFormat,
+                                             const GLsizei                 theNbSamples = 0);
+
+  //! (Re-)initialize FBO with properties taken from another FBO.
+  Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx,
+                             const OpenGl_FrameBuffer&     theFbo)
+  {
+    return InitLazy (theGlCtx, theFbo.myVPSizeX, theFbo.myVPSizeY, theFbo.myColorFormat, theFbo.myDepthFormat, theFbo.myNbSamples);
+  }
 
   //! (Re-)initialize FBO with specified dimensions.
   //! The Render Buffer Objects will be used for Color, Depth and Stencil attachments (as opposite to textures).
-  //! @param theGlCtx         currently bound OpenGL context
-  //! @param theViewportSizeX required viewport size, the actual dimensions of FBO might be greater
-  //! @param theViewportSizeY required viewport size, the actual dimensions of FBO might be greater
+  //! @param theGlCtx       currently bound OpenGL context
+  //! @param theSizeX       render buffer width
+  //! @param theSizeY       render buffer height
+  //! @param theColorFormat color         render buffer sized format, e.g. GL_RGBA8
+  //! @param theDepthFormat depth-stencil render buffer sized format, e.g. GL_DEPTH24_STENCIL8
   //! @param theColorRBufferFromWindow when specified - should be ID of already initialized RB object, which will be released within this class
   Standard_EXPORT Standard_Boolean InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
-                                               const GLsizei                 theViewportSizeX,
-                                               const GLsizei                 theViewportSizeY,
+                                               const GLsizei                 theSizeX,
+                                               const GLsizei                 theSizeY,
+                                               const GLint                   theColorFormat,
+                                               const GLint                   theDepthFormat,
                                                const GLuint                  theColorRBufferFromWindow = 0);
 
   //! Initialize class from currently bound FBO.
@@ -163,7 +198,9 @@ protected:
 
   GLsizei                myVPSizeX;             //!< viewport width  (should be <= texture width)
   GLsizei                myVPSizeY;             //!< viewport height (should be <= texture height)
-  GLint                  myTextFormat;          //!< GL_RGB, GL_RGBA,...
+  GLsizei                myNbSamples;           //!< number of MSAA samples
+  GLint                  myColorFormat;         //!< sized format for color         texture, GL_RGBA8 by default
+  GLint                  myDepthFormat;         //!< sized format for depth-stencil texture, GL_DEPTH24_STENCIL8 by default
   GLuint                 myGlFBufferId;         //!< FBO object ID
   GLuint                 myGlColorRBufferId;    //!< color         Render Buffer object (alternative to myColorTexture)
   GLuint                 myGlDepthRBufferId;    //!< depth-stencil Render Buffer object (alternative to myDepthStencilTexture)
index d75d686..50a1116 100644 (file)
   // OpenGL ES 3.0+ or GL_OES_element_index_uint extension
   #define GL_UNSIGNED_INT 0x1405
 
+  // OpenGL ES 3.1+
+  #define GL_TEXTURE_2D_MULTISAMPLE 0x9100
+  #define GL_MAX_SAMPLES  0x8D57
+
   // in core since OpenGL ES 3.0, extension GL_EXT_texture_rg
   #define GL_RED   0x1903
   #define GL_R8    0x8229
   #define GL_UNSIGNED_INT_24_8              0x84FA
   #define GL_DEPTH24_STENCIL8               0x88F0
 
+  // OpenGL ES 3.0+
+  #define GL_DEPTH_COMPONENT32F             0x8CAC
+  #define GL_DEPTH32F_STENCIL8              0x8CAD
+  #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
+
   #define GL_READ_FRAMEBUFFER               0x8CA8
   #define GL_DRAW_FRAMEBUFFER               0x8CA9
 
@@ -702,6 +711,11 @@ public: //! @name OpenGL ES 3.0
   typedef void (*glBlitFramebuffer_t)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
   glBlitFramebuffer_t glBlitFramebuffer;
 
+public: //! @name OpenGL ES 3.1
+
+  typedef void (*glTexStorage2DMultisample_t)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+  glTexStorage2DMultisample_t glTexStorage2DMultisample;
+
 #else // OpenGL ES vs. desktop
 
 public: //! @name OpenGL 1.2
index dde0ff7..256a989 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <OpenGl_ArbFBO.hxx>
 #include <OpenGl_Context.hxx>
-#include <OpenGl_GlCore15.hxx>
+#include <OpenGl_GlCore32.hxx>
 #include <Graphic3d_TextureParams.hxx>
 #include <TCollection_ExtendedString.hxx>
 #include <Standard_Assert.hxx>
@@ -661,6 +661,58 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
 }
 
 // =======================================================================
+// function : Init2DMultisample
+// purpose  :
+// =======================================================================
+bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
+                                        const GLsizei                 theNbSamples,
+                                        const GLint                   theTextFormat,
+                                        const GLsizei                 theSizeX,
+                                        const GLsizei                 theSizeY)
+{
+  if (!Create (theCtx)
+    || theNbSamples > theCtx->MaxMsaaSamples()
+    || theNbSamples < 1)
+  {
+    return false;
+  }
+
+  const GLsizei aNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
+  myTarget = GL_TEXTURE_2D_MULTISAMPLE;
+  if(theSizeX > theCtx->MaxTextureSize()
+  || theSizeY > theCtx->MaxTextureSize())
+  {
+    return false;
+  }
+
+  Bind (theCtx);
+  //myTextFormat = theTextFormat;
+#if !defined(GL_ES_VERSION_2_0)
+  if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
+  {
+    theCtx->Functions()->glTexStorage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
+  }
+  else
+  {
+    theCtx->Functions()->glTexImage2DMultisample   (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
+  }
+#else
+  theCtx->Functions()  ->glTexStorage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
+#endif
+  if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
+  {
+    Unbind (theCtx);
+    return false;
+  }
+
+  mySizeX = theSizeX;
+  mySizeY = theSizeY;
+
+  Unbind (theCtx);
+  return true;
+}
+
+// =======================================================================
 // function : InitRectangle
 // purpose  :
 // =======================================================================
index 1a1a0ed..06905e9 100644 (file)
@@ -247,6 +247,13 @@ public:
                              const Graphic3d_TypeOfTexture theType,
                              const Image_PixMap*           theImage = NULL);
 
+  //! Initialize the 2D multisampling texture using glTexImage2DMultisample().
+  Standard_EXPORT bool Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
+                                          const GLsizei                 theNbSamples,
+                                          const GLint                   theTextFormat,
+                                          const GLsizei                 theSizeX,
+                                          const GLsizei                 theSizeY);
+
   //! Allocates texture rectangle with specified format and size.
   //! \note Texture data is not initialized (will contain trash).
   Standard_EXPORT bool InitRectangle (const Handle(OpenGl_Context)& theCtx,
index b572396..6ecb61d 100644 (file)
@@ -76,6 +76,9 @@ OpenGl_View::OpenGl_View (const Handle(Graphic3d_StructureManager)& theMgr,
   myToShowGradTrihedron  (false),
   myStateCounter         (theCounter),
   myLastLightSourceState (0, 0),
+  myFboColorFormat       (GL_RGBA8),
+  myFboDepthFormat       (GL_DEPTH24_STENCIL8),
+  myToFlipOutput         (Standard_False),
   myFrameCounter         (0),
   myHasFboBlit           (Standard_True),
   myTransientDrawToFront (Standard_True),
@@ -106,6 +109,12 @@ OpenGl_View::OpenGl_View (const Handle(Graphic3d_StructureManager)& theMgr,
   myMainSceneFbos[1]      = new OpenGl_FrameBuffer();
   myImmediateSceneFbos[0] = new OpenGl_FrameBuffer();
   myImmediateSceneFbos[1] = 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();
 }
 
 // =======================================================================
@@ -152,6 +161,8 @@ void OpenGl_View::ReleaseGlResources (const Handle(OpenGl_Context)& theCtx)
   myMainSceneFbos[1]     ->Release (theCtx.operator->());
   myImmediateSceneFbos[0]->Release (theCtx.operator->());
   myImmediateSceneFbos[1]->Release (theCtx.operator->());
+  myOpenGlFBO            ->Release (theCtx.operator->());
+  myOpenGlFBO2           ->Release (theCtx.operator->());
   myFullScreenQuad        .Release (theCtx.operator->());
   myFullScreenQuadFlip    .Release (theCtx.operator->());
 
index b256b4e..c52b86c 100644 (file)
@@ -545,7 +545,7 @@ private:
   OpenGl_VertexBuffer* initBlitQuad (const Standard_Boolean theToFlip);
 
   //! Blend together views pair into stereo image.
-  void drawStereoPair();
+  void drawStereoPair (OpenGl_FrameBuffer* theDrawFbo);
 
 protected:
 
@@ -599,6 +599,8 @@ protected: //! @name Rendering properties
 
   //! Two framebuffers (left and right views) store cached main presentation
   //! of the view (without presentation of immediate layers).
+  GLint                      myFboColorFormat;        //!< sized format for color attachments
+  GLint                      myFboDepthFormat;        //!< sized format for depth-stencil attachments
   Handle(OpenGl_FrameBuffer) myMainSceneFbos[2];
   Handle(OpenGl_FrameBuffer) myImmediateSceneFbos[2]; //!< Additional buffers for immediate layer in stereo mode.
   OpenGl_VertexBuffer        myFullScreenQuad;        //!< Vertices for full-screen quad rendering.
@@ -1034,6 +1036,7 @@ protected: //! @name fields related to ray-tracing
   Handle(OpenGl_FrameBuffer) myRaytraceFBO2[2];
   //! Framebuffer (FBO) for preliminary OpenGL output.
   Handle(OpenGl_FrameBuffer) myOpenGlFBO;
+  Handle(OpenGl_FrameBuffer) myOpenGlFBO2;
 
   //! Vertex buffer (VBO) for drawing dummy quad.
   OpenGl_VertexBuffer myRaytraceScreenQuad;
index 93b9db1..5f53f44 100644 (file)
@@ -440,7 +440,7 @@ Standard_Boolean OpenGl_View::Print (const Aspect_Handle    thePrinterDC,
         initBufferTiling (aFrameWidth, aFrameHeight, width, height);
 
       // try to initialize framebuffer
-      if (aFrameBuffer->Init (aCtx, aFrameWidth, aFrameHeight))
+      if (aFrameBuffer->Init (aCtx, aFrameWidth, aFrameHeight, GL_RGBA8, GL_DEPTH24_STENCIL8))
       {
 #ifdef HAVE_FREEIMAGE
         // try to allocate fipImage and necessary resources
index 27e9b00..c0eacbb 100644 (file)
@@ -1586,18 +1586,6 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
     return myRaytraceInitStatus == OpenGl_RT_INIT;
   }
 
-  if (myRaytraceFBO1[0].IsNull())
-  {
-    myRaytraceFBO1[0] = new OpenGl_FrameBuffer (GL_RGBA32F);
-    myRaytraceFBO1[1] = new OpenGl_FrameBuffer (GL_RGBA32F);
-  }
-
-  if (myRaytraceFBO2[0].IsNull())
-  {
-    myRaytraceFBO2[0] = new OpenGl_FrameBuffer (GL_RGBA32F);
-    myRaytraceFBO2[1] = new OpenGl_FrameBuffer (GL_RGBA32F);
-  }
-
   const GLfloat aVertices[] = { -1.f, -1.f,  0.f,
                                 -1.f,  1.f,  0.f,
                                  1.f,  1.f,  0.f,
@@ -1632,11 +1620,10 @@ inline void nullifyResource (const Handle(OpenGl_Context)& theGlContext,
 // =======================================================================
 void OpenGl_View::releaseRaytraceResources (const Handle(OpenGl_Context)& theGlContext)
 {
-  nullifyResource (theGlContext, myOpenGlFBO);
-  nullifyResource (theGlContext, myRaytraceFBO1[0]);
-  nullifyResource (theGlContext, myRaytraceFBO2[0]);
-  nullifyResource (theGlContext, myRaytraceFBO1[1]);
-  nullifyResource (theGlContext, myRaytraceFBO2[1]);
+  myRaytraceFBO1[0]->Release (theGlContext.operator->());
+  myRaytraceFBO1[1]->Release (theGlContext.operator->());
+  myRaytraceFBO2[0]->Release (theGlContext.operator->());
+  myRaytraceFBO2[1]->Release (theGlContext.operator->());
 
   nullifyResource (theGlContext, myRaytraceShader);
   nullifyResource (theGlContext, myPostFSAAShader);
@@ -1682,22 +1669,14 @@ Standard_Boolean OpenGl_View::updateRaytraceBuffers (const Standard_Integer
     return Standard_True;
   }
 
-  if ( myRaytraceFBO1[0]->GetVPSizeX() != theSizeX
-    || myRaytraceFBO1[0]->GetVPSizeY() != theSizeY)
-  {
-    myRaytraceFBO1[0]->Init (theGlContext, theSizeX, theSizeY);
-    myRaytraceFBO2[0]->Init (theGlContext, theSizeX, theSizeY);
-  }
+  myRaytraceFBO1[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
+  myRaytraceFBO2[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
 
   // Init second set of buffers for stereographic rendering.
   if (myCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
   {
-    if (myRaytraceFBO1[1]->GetVPSizeX() != theSizeX
-     || myRaytraceFBO1[1]->GetVPSizeY() != theSizeY)
-    {
-      myRaytraceFBO1[1]->Init (theGlContext, theSizeX, theSizeY);
-      myRaytraceFBO2[1]->Init (theGlContext, theSizeX, theSizeY);
-    }
+    myRaytraceFBO1[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
+    myRaytraceFBO2[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
   }
   else
   {
index 5fb382d..542360e 100644 (file)
@@ -289,6 +289,13 @@ void OpenGl_View::Redraw()
   Standard_Integer aSizeX = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeX() : myWindow->Width();
   Standard_Integer aSizeY = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeY() : myWindow->Height();
 
+  // determine multisampling parameters
+  Standard_Integer aNbSamples = Max (Min (myRenderParams.NbMsaaSamples, aCtx->MaxMsaaSamples()), 0);
+  if (aNbSamples != 0)
+  {
+    aNbSamples = OpenGl_Context::GetPowerOfTwo (aNbSamples, aCtx->MaxMsaaSamples());
+  }
+
   if ( aFrameBuffer == NULL
    && !aCtx->DefaultFrameBuffer().IsNull()
    &&  aCtx->DefaultFrameBuffer()->IsValid())
@@ -297,20 +304,23 @@ void OpenGl_View::Redraw()
   }
 
   if (myHasFboBlit
-   && (myTransientDrawToFront || aProjectType == Graphic3d_Camera::Projection_Stereo))
+   && (myTransientDrawToFront
+    || aProjectType == Graphic3d_Camera::Projection_Stereo
+    || aNbSamples != 0))
   {
     if (myMainSceneFbos[0]->GetVPSizeX() != aSizeX
-     || myMainSceneFbos[0]->GetVPSizeY() != aSizeY)
+     || myMainSceneFbos[0]->GetVPSizeY() != aSizeY
+     || myMainSceneFbos[0]->NbSamples()  != aNbSamples)
     {
       // prepare FBOs containing main scene
       // for further blitting and rendering immediate presentations on top
       if (aCtx->core20fwd != NULL)
       {
-        myMainSceneFbos[0]->Init (aCtx, aSizeX, aSizeY);
+        myMainSceneFbos[0]->Init (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, aNbSamples);
       }
       if (!aCtx->caps->useSystemBuffer && myMainSceneFbos[0]->IsValid())
       {
-        myImmediateSceneFbos[0]->InitLazy (aCtx, aSizeX, aSizeY);
+        myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]);
       }
     }
   }
@@ -329,7 +339,7 @@ void OpenGl_View::Redraw()
   if (aProjectType == Graphic3d_Camera::Projection_Stereo
    && myMainSceneFbos[0]->IsValid())
   {
-    myMainSceneFbos[1]->InitLazy (aCtx, aSizeX, aSizeY);
+    myMainSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0]);
     if (!myMainSceneFbos[1]->IsValid())
     {
       // no enough memory?
@@ -341,8 +351,8 @@ void OpenGl_View::Redraw()
     }
     else if (!aCtx->HasStereoBuffers() || aStereoMode != Graphic3d_StereoMode_QuadBuffer)
     {
-      myImmediateSceneFbos[0]->InitLazy (aCtx, aSizeX, aSizeY);
-      myImmediateSceneFbos[1]->InitLazy (aCtx, aSizeX, aSizeY);
+      myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]);
+      myImmediateSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0]);
       if (!myImmediateSceneFbos[0]->IsValid()
        || !myImmediateSceneFbos[1]->IsValid())
       {
@@ -407,8 +417,7 @@ void OpenGl_View::Redraw()
 
     if (anImmFbos[0] != NULL)
     {
-      bindDefaultFbo (aFrameBuffer);
-      drawStereoPair();
+      drawStereoPair (aFrameBuffer);
     }
   }
   else
@@ -584,8 +593,7 @@ void OpenGl_View::RedrawImmediate()
                               Standard_True) || toSwap;
     if (anImmFbos[0] != NULL)
     {
-      bindDefaultFbo (aFrameBuffer);
-      drawStereoPair();
+      drawStereoPair (aFrameBuffer);
     }
   }
   else
@@ -1045,15 +1053,7 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
     {
       const Standard_Integer aSizeX = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeX() : myWindow->Width();
       const Standard_Integer aSizeY = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeY() : myWindow->Height();
-
-      if (myOpenGlFBO.IsNull())
-        myOpenGlFBO = new OpenGl_FrameBuffer;
-
-      if (myOpenGlFBO->GetVPSizeX() != aSizeX
-       || myOpenGlFBO->GetVPSizeY() != aSizeY)
-      {
-        myOpenGlFBO->Init (aCtx, aSizeX, aSizeY);
-      }
+      myOpenGlFBO ->InitLazy (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, 0);
 
       if (myRaytraceFilter.IsNull())
         myRaytraceFilter = new OpenGl_RaytraceFilter;
@@ -1476,26 +1476,46 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
 #endif
   aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 
-/*#if !defined(GL_ES_VERSION_2_0)
-  if (aCtx->arbFBOBlit != NULL)
+#if !defined(GL_ES_VERSION_2_0)
+  if (aCtx->arbFBOBlit != NULL
+   && theReadFbo->NbSamples() != 0)
   {
+    GLbitfield aCopyMask = 0;
     theReadFbo->BindReadBuffer (aCtx);
     if (theDrawFbo != NULL
      && theDrawFbo->IsValid())
     {
       theDrawFbo->BindDrawBuffer (aCtx);
+      if (theDrawFbo->HasColor()
+       && theReadFbo->HasColor())
+      {
+        aCopyMask |= GL_COLOR_BUFFER_BIT;
+      }
+      if (theDrawFbo->HasDepth()
+       && theReadFbo->HasDepth())
+      {
+        aCopyMask |= GL_DEPTH_BUFFER_BIT;
+      }
     }
     else
     {
+      if (theReadFbo->HasColor())
+      {
+        aCopyMask |= GL_COLOR_BUFFER_BIT;
+      }
+      if (theReadFbo->HasDepth())
+      {
+        aCopyMask |= GL_DEPTH_BUFFER_BIT;
+      }
       aCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
     }
+
     // we don't copy stencil buffer here... does it matter for performance?
     aCtx->arbFBOBlit->glBlitFramebuffer (0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(),
                                          0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(),
-                                         GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
-
+                                         aCopyMask, GL_NEAREST);
     if (theDrawFbo != NULL
-      && theDrawFbo->IsValid())
+     && theDrawFbo->IsValid())
     {
       theDrawFbo->BindBuffer (aCtx);
     }
@@ -1505,7 +1525,7 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
     }
   }
   else
-#endif*/
+#endif
   {
     aCtx->core20fwd->glDepthFunc (GL_ALWAYS);
     aCtx->core20fwd->glDepthMask (GL_TRUE);
@@ -1550,8 +1570,10 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
 // function : drawStereoPair
 // purpose  :
 // =======================================================================
-void OpenGl_View::drawStereoPair()
+void OpenGl_View::drawStereoPair (OpenGl_FrameBuffer* theDrawFbo)
 {
+  const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
+  bindDefaultFbo (theDrawFbo);
   OpenGl_FrameBuffer* aPair[2] =
   {
     myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
@@ -1571,6 +1593,33 @@ void OpenGl_View::drawStereoPair()
     return;
   }
 
+  if (aPair[0]->NbSamples() != 0)
+  {
+    // resolve MSAA buffers before drawing
+    if (!myOpenGlFBO ->InitLazy (aCtx, aPair[0]->GetVPSizeX(), aPair[0]->GetVPSizeY(), myFboColorFormat, myFboDepthFormat, 0)
+     || !myOpenGlFBO2->InitLazy (aCtx, aPair[0]->GetVPSizeX(), aPair[0]->GetVPSizeY(), myFboColorFormat, 0, 0))
+    {
+      aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
+                         GL_DEBUG_TYPE_ERROR_ARB,
+                         0,
+                         GL_DEBUG_SEVERITY_HIGH_ARB,
+                         "Error! Unable to allocate FBO for blitting stereo pair");
+      bindDefaultFbo (theDrawFbo);
+      return;
+    }
+
+    if (!blitBuffers (aPair[0], myOpenGlFBO .operator->(), Standard_False)
+     || !blitBuffers (aPair[1], myOpenGlFBO2.operator->(), Standard_False))
+    {
+      bindDefaultFbo (theDrawFbo);
+      return;
+    }
+
+    aPair[0] = myOpenGlFBO .operator->();
+    aPair[1] = myOpenGlFBO2.operator->();
+    bindDefaultFbo (theDrawFbo);
+  }
+
   struct
   {
     Standard_Integer left;
@@ -1604,7 +1653,6 @@ void OpenGl_View::drawStereoPair()
     std::swap (aPair[0], aPair[1]);
   }
 
-  Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
   aCtx->core20fwd->glDepthFunc (GL_ALWAYS);
   aCtx->core20fwd->glDepthMask (GL_TRUE);
   aCtx->core20fwd->glEnable (GL_DEPTH_TEST);
index 2e85cca..fc3dc6c 100644 (file)
@@ -297,7 +297,7 @@ void OpenGl_Window::Init()
     ::glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myHeight);
     ::glBindRenderbuffer (GL_RENDERBUFFER, 0);
 
-    if (!aDefFbo->InitWithRB (myGlContext, myWidth, myHeight, aWinRBColor))
+    if (!aDefFbo->InitWithRB (myGlContext, myWidth, myHeight, GL_RGBA8, GL_DEPTH24_STENCIL8, aWinRBColor))
     {
       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO creation failed");
       Aspect_GraphicDeviceDefinitionError::Raise (aMsg.ToCString());
index ede088c..03f3ba4 100644 (file)
@@ -1099,7 +1099,7 @@ Graphic3d_PtrFrameBuffer OpenGl_Workspace::FBOCreate (const Standard_Integer the
   // create the FBO
   const Handle(OpenGl_Context)& aCtx = GetGlContext();
   OpenGl_FrameBuffer* aFrameBuffer = new OpenGl_FrameBuffer();
-  if (!aFrameBuffer->Init (aCtx, theWidth, theHeight))
+  if (!aFrameBuffer->Init (aCtx, theWidth, theHeight, GL_RGBA8, GL_DEPTH24_STENCIL8, 0))
   {
     aFrameBuffer->Release (aCtx.operator->());
     delete aFrameBuffer;
index 6e92634..9642900 100644 (file)
@@ -8267,10 +8267,11 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
     }
     theDI << "\n";
+    theDI << "msaa:         " <<  aParams.NbMsaaSamples << "\n";
+    theDI << "rayDepth:     " <<  aParams.RaytracingDepth                             << "\n";
     theDI << "fsaa:         " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
     theDI << "shadows:      " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
     theDI << "reflections:  " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
-    theDI << "rayDepth:     " <<  aParams.RaytracingDepth                             << "\n";
     theDI << "gleam:        " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
     theDI << "GI:           " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
     theDI << "blocked RNG:  " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
@@ -8345,6 +8346,30 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
 
       aParams.Method = Graphic3d_RM_RASTERIZATION;
     }
+    else if (aFlag == "-msaa")
+    {
+      if (toPrint)
+      {
+        theDI << aParams.NbMsaaSamples << " ";
+        continue;
+      }
+      else if (++anArgIter >= theArgNb)
+      {
+        std::cerr << "Error: wrong syntax at argument '" << anArg << "'\n";
+        return 1;
+      }
+
+      const Standard_Integer aNbSamples = Draw::Atoi (theArgVec[anArgIter]);
+      if (aNbSamples < 0)
+      {
+        std::cerr << "Error: invalid number of MSAA samples " << aNbSamples << ".\n";
+        return 1;
+      }
+      else
+      {
+        aParams.NbMsaaSamples = aNbSamples;
+      }
+    }
     else if (aFlag == "-raydepth"
           || aFlag == "-ray_depth")
     {
@@ -9270,8 +9295,9 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     __FILE__, VRenderParams, group);
   theCommands.Add("vrenderparams",
     "\n    Manages rendering parameters: "
-    "\n      '-rayTrace'             Enables  GPU ray-tracing"
     "\n      '-raster'               Disables GPU ray-tracing"
+    "\n      '-msaa         0..4'    Specifies number of samples for MSAA"
+    "\n      '-rayTrace'             Enables  GPU ray-tracing"
     "\n      '-rayDepth     0..10'   Defines maximum ray-tracing depth"
     "\n      '-shadows      on|off'  Enables/disables shadows rendering"
     "\n      '-reflections  on|off'  Enables/disables specular reflections"
diff --git a/tests/v3d/glsl/msaa b/tests/v3d/glsl/msaa
new file mode 100644 (file)
index 0000000..6885bee
--- /dev/null
@@ -0,0 +1,24 @@
+puts "========"
+puts "Multisampling FBOs"
+puts "========"
+
+pload MODELING VISUALIZATION
+box b 2 3 1
+vclear
+vclose ALL
+vinit View1 w=512 h=512
+vsetgradientbg 180 200 255 180 180 180 2
+vsetdispmode 0
+vdisplay b
+vfit
+vrotate 0.5 0 0
+vzbufftrihedron
+
+vrenderparams -msaa 0
+vdump $::imagedir/${::casename}_0.png
+vrenderparams -msaa 2
+vdump $::imagedir/${::casename}_2.png
+vrenderparams -msaa 4
+vdump $::imagedir/${::casename}_4.png
+vrenderparams -msaa 8
+vdump $::imagedir/${::casename}_8.png