]> OCCT Git - occt.git/commitdiff
0032648: Visualization, TKOpenGles - support MSAA anti-aliasing within WebGL 2.0
authorkgv <kgv@opencascade.com>
Tue, 2 Nov 2021 13:23:25 +0000 (16:23 +0300)
committerinv <inv@opencascade.com>
Sun, 21 Nov 2021 09:42:10 +0000 (12:42 +0300)
OpenGl_FrameBuffer::Init() now creates MSAA render buffer in case if MSAA textures are unsupported.
In this case OpenGl_View::prepareFrameBuffers() creates MSAA render buffer for main content
and non-MSAA FBO for immediate content as blitting of MSAA render buffers into MSAA targets is unsupported by OpenGL ES 3.0.

env.bat.in has been corrected to include path to custom ANGLE (GLES2_DIR)
in front of Qt which might include its own older ANGLE build.

adm/templates/env.bat.in
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_FrameBuffer.cxx
src/OpenGl/OpenGl_FrameBuffer.hxx
src/OpenGl/OpenGl_Texture.cxx
src/OpenGl/OpenGl_View.cxx
src/OpenGl/OpenGl_Window.cxx

index 94e8db5cea9847e8bbdc33d20eaa55821cd93db5..538ad7cc676c7405afc77c5b0604b32f478f55bf 100644 (file)
@@ -131,6 +131,10 @@ if exist "%CASROOT%\custom.bat" (
   call "%CASROOT%\custom.bat" %VCVER% %ARCH% %CASDEB%
 )
 
+if not ["%QTDIR%"] == [""] (
+  set "PATH=%QTDIR%/bin;%PATH%"
+  set "QT_PLUGIN_PATH=%QTDIR%/plugins"
+)
 if not ["%TCL_DIR%"] == [""]           set "PATH=%TCL_DIR%;%PATH%"
 if not ["%TK_DIR%"] == [""]            set "PATH=%TK_DIR%;%PATH%"
 if not ["%FREETYPE_DIR%"] == [""]      set "PATH=%FREETYPE_DIR%;%PATH%"
@@ -141,10 +145,6 @@ if not ["%TBB_DIR%"] == [""]           set "PATH=%TBB_DIR%;%PATH%"
 if not ["%VTK_DIR%"] == [""]           set "PATH=%VTK_DIR%;%PATH%"
 if not ["%FFMPEG_DIR%"] == [""]        set "PATH=%FFMPEG_DIR%;%PATH%"
 if not ["%OPENVR_DIR%"] == [""]        set "PATH=%OPENVR_DIR%;%PATH%"
-if not ["%QTDIR%"] == [""] (
-  set "PATH=%QTDIR%/bin;%PATH%"
-  set "QT_PLUGIN_PATH=%QTDIR%/plugins"
-)
 
 rem ----- Set path to 3rd party and OCCT libraries -----
 if not "%CSF_OCCTBinPath%" == "" (
index 38c27c2015547cb35a75b4bd8abb602f8551b7e6..da868a036cd27a135617b96b002ea14440e75954 100644 (file)
@@ -184,6 +184,13 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myClippingState (),
   myGlLibHandle (NULL),
   myFuncs (new OpenGl_GlFunctions()),
+  myGapi (
+#if defined(GL_ES_VERSION_2_0)
+    Aspect_GraphicsLibrary_OpenGLES
+#else
+    Aspect_GraphicsLibrary_OpenGL
+#endif
+  ),
   mySupportedFormats (new Image_SupportedFormats()),
   myAnisoMax   (1),
   myTexClamp   (GL_CLAMP_TO_EDGE),
@@ -200,6 +207,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myGlVerMinor (0),
   myIsInitialized (Standard_False),
   myIsStereoBuffers (Standard_False),
+  myHasMsaaTextures (Standard_False),
   myIsGlNormalizeEnabled (Standard_False),
   mySpriteTexUnit (Graphic3d_TextureUnit_PointSprite),
   myHasRayTracing (Standard_False),
@@ -1386,6 +1394,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   // read version
   myGlVerMajor = 0;
   myGlVerMinor = 0;
+  myHasMsaaTextures = false;
   myMaxMsaaSamples = 0;
   myMaxDrawBuffers = 1;
   myMaxColorAttachments = 1;
@@ -1573,25 +1582,26 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   myClippingState.Init();
 
 #if defined(GL_ES_VERSION_2_0)
-  if (IsGlGreaterEqual (3, 1)
-   && myFuncs->glTexStorage2DMultisample != NULL)
+  if (IsGlGreaterEqual (3, 0))
   {
-    // MSAA RenderBuffers have been defined in OpenGL ES 3.0,
-    // but MSAA Textures - only in OpenGL ES 3.1+
+    // MSAA RenderBuffers have been defined in OpenGL ES 3.0, but MSAA Textures - only in OpenGL ES 3.1+
+    myHasMsaaTextures = IsGlGreaterEqual (3, 1)
+                     && myFuncs->glTexStorage2DMultisample != NULL;
     ::glGetIntegerv (GL_MAX_SAMPLES, &myMaxMsaaSamples);
   }
 #else
   if (core30 != NULL)
   {
-    // MSAA RenderBuffers have been defined in OpenGL 3.0,
-    // but MSAA Textures - only in OpenGL 3.2+
+    // MSAA RenderBuffers have been defined in OpenGL 3.0, but MSAA Textures - only in OpenGL 3.2+
     if (core32 != NULL)
     {
+      myHasMsaaTextures = true;
       ::glGetIntegerv (GL_MAX_SAMPLES, &myMaxMsaaSamples);
     }
     else if (CheckExtension ("GL_ARB_texture_multisample")
           && myFuncs->glTexImage2DMultisample != NULL)
     {
+      myHasMsaaTextures = true;
       GLint aNbColorSamples = 0, aNbDepthSamples = 0;
       ::glGetIntegerv (GL_MAX_COLOR_TEXTURE_SAMPLES, &aNbColorSamples);
       ::glGetIntegerv (GL_MAX_DEPTH_TEXTURE_SAMPLES, &aNbDepthSamples);
@@ -1599,6 +1609,10 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     }
   }
 #endif
+  if (myMaxMsaaSamples <= 1)
+  {
+    myHasMsaaTextures = false;
+  }
 
 #if !defined(GL_ES_VERSION_2_0)
   if (core32 != NULL && isCoreProfile)
@@ -2370,6 +2384,32 @@ Handle(OpenGl_FrameBuffer) OpenGl_Context::SetDefaultFrameBuffer (const Handle(O
   return aFbo;
 }
 
+// =======================================================================
+// function : IsRender
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_Context::IsRender() const
+{
+#if !defined(GL_ES_VERSION_2_0)
+  return myRenderMode == GL_RENDER;
+#else
+  return Standard_True;
+#endif
+}
+
+// =======================================================================
+// function : IsFeedback
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_Context::IsFeedback() const
+{
+#if !defined(GL_ES_VERSION_2_0)
+  return myRenderMode == GL_FEEDBACK;
+#else
+  return Standard_False;
+#endif
+}
+
 // =======================================================================
 // function : SetShadingMaterial
 // purpose  :
index 27849d3169030ca5807306cedff086be03b76bf6..e0cf8cdf1e46197b3f47a706762c31e027af9913 100644 (file)
@@ -20,6 +20,7 @@
 #include <Aspect_HatchStyle.hxx>
 #include <Aspect_Drawable.hxx>
 #include <Aspect_Display.hxx>
+#include <Aspect_GraphicsLibrary.hxx>
 #include <Aspect_RenderingContext.hxx>
 #include <Aspect_TypeOfLine.hxx>
 #include <NCollection_DataMap.hxx>
@@ -330,6 +331,9 @@ public:
     return (theFuncPtr != NULL);
   }
 
+  //! Return active graphics library.
+  Aspect_GraphicsLibrary GraphicsLibrary() const { return myGapi; }
+
   //! @return true if detected GL version is greater or equal to requested one.
   inline Standard_Boolean IsGlGreaterEqual (const Standard_Integer theVerMajor,
                                             const Standard_Integer theVerMinor) const
@@ -367,24 +371,10 @@ public:
   Standard_EXPORT Standard_Boolean SetSwapInterval (const Standard_Integer theInterval);
 
   //! Return true if active mode is GL_RENDER (cached state)
-  Standard_Boolean IsRender() const
-  {
-  #if !defined(GL_ES_VERSION_2_0)
-    return myRenderMode == GL_RENDER;
-  #else
-    return Standard_True;
-  #endif
-  }
+  Standard_EXPORT Standard_Boolean IsRender() const;
 
   //! Return true if active mode is GL_FEEDBACK (cached state)
-  Standard_Boolean IsFeedback() const
-  {
-  #if !defined(GL_ES_VERSION_2_0)
-    return myRenderMode == GL_FEEDBACK;
-  #else
-    return Standard_False;
-  #endif
-  }
+  Standard_EXPORT Standard_Boolean IsFeedback() const;
 
   //! This function retrieves information from GL about free GPU memory that is:
   //!  - OS-dependent. On some OS it is per-process and on others - for entire system.
@@ -480,11 +470,9 @@ public:
   //! @return true if texture parameters GL_TEXTURE_BASE_LEVEL/GL_TEXTURE_MAX_LEVEL are supported.
   Standard_Boolean HasTextureBaseLevel() const
   {
-  #if !defined(GL_ES_VERSION_2_0)
-    return IsGlGreaterEqual (1, 2);
-  #else
-    return IsGlGreaterEqual (3, 0);
-  #endif
+    return myGapi == Aspect_GraphicsLibrary_OpenGLES
+         ? IsGlGreaterEqual (3, 0)
+         : IsGlGreaterEqual (1, 2);
   }
 
   //! Return map of supported texture formats.
@@ -507,6 +495,9 @@ public:
   //! Return texture unit to be used for sprites (Graphic3d_TextureUnit_PointSprite by default).
   Graphic3d_TextureUnit SpriteTextureUnit() const { return mySpriteTexUnit; }
 
+  //! @return true if MSAA textures are supported.
+  Standard_Boolean HasTextureMultisampling() const { return myHasMsaaTextures; }
+
   //! @return value for GL_MAX_SAMPLES
   Standard_Integer MaxMsaaSamples() const { return myMaxMsaaSamples; }
 
@@ -721,16 +712,8 @@ public:
   Standard_EXPORT Standard_Boolean IncludeMessage (const unsigned int theSource,
                                                    const unsigned int theId);
 
-  //! @return true if OpenGl context supports left and
-  //! right rendering buffers.
-  Standard_Boolean HasStereoBuffers() const
-  {
-  #if !defined(GL_ES_VERSION_2_0)
-    return myIsStereoBuffers;
-  #else
-    return Standard_False;
-  #endif
-  }
+  //! @return true if OpenGl context supports left and right rendering buffers.
+  Standard_Boolean HasStereoBuffers() const { return myIsStereoBuffers; }
 
 public: //! @name methods to alter or retrieve current state
 
@@ -1110,6 +1093,7 @@ private: // context info
   void*            myGlLibHandle;          //!< optional handle to GL library
   NCollection_Handle<OpenGl_GlFunctions>
                    myFuncs;                //!< mega structure for all GL functions
+  Aspect_GraphicsLibrary myGapi;           //!< GAPI name
   Handle(Image_SupportedFormats)
                    mySupportedFormats;     //!< map of supported texture formats
   Standard_Integer myAnisoMax;             //!< maximum level of anisotropy texture filter
@@ -1127,6 +1111,7 @@ private: // context info
   Standard_Integer myGlVerMinor;           //!< cached GL version minor number
   Standard_Boolean myIsInitialized;        //!< flag indicates initialization state
   Standard_Boolean myIsStereoBuffers;      //!< context supports stereo buffering
+  Standard_Boolean myHasMsaaTextures;      //!< context supports MSAA textures
   Standard_Boolean myIsGlNormalizeEnabled; //!< GL_NORMALIZE flag
                                            //!< Used to tell OpenGl that normals should be normalized
   Graphic3d_TextureUnit mySpriteTexUnit;   //!< sampler2D occSamplerPointSprite, texture unit for point sprite texture
index 1864da9a4fb7d624443fd30fad7043099ea19540..6ee169946ad8c3ffebb29b72fe22c01bc68ff521 100644 (file)
@@ -19,6 +19,7 @@
 #include <OpenGl_Texture.hxx>
 
 #include <Standard_Assert.hxx>
+#include <Standard_NotImplemented.hxx>
 #include <TCollection_ExtendedString.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource)
@@ -363,6 +364,13 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
     return Standard_False;
   }
 
+  if (theNbSamples != 0
+  && !theGlContext->HasTextureMultisampling()
+   && theGlContext->MaxMsaaSamples() > 1)
+  {
+    return InitRenderBuffer (theGlContext, theSize, theColorFormats, theDepthFormat, theNbSamples);
+  }
+
   myIsOwnColor  = true;
   myIsOwnBuffer = true;
   myIsOwnDepth  = true;
@@ -429,6 +437,16 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
       theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
       theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, aDepthStencilFormat, aSizeX, aSizeY);
       theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+      const GLenum aRendImgErr = theGlContext->core11fwd->glGetError();
+      if (aRendImgErr != GL_NO_ERROR)
+      {
+        theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                                   TCollection_AsciiString ("Error: FBO depth render buffer ") + aSizeX + "x" + aSizeY
+                                   + " IF: " + OpenGl_TextureFormat::FormatFormat (aDepthStencilFormat)
+                                   + " can not be created with error " + OpenGl_Context::FormatGlError (aRendImgErr) + ".");
+        Release (theGlContext.get());
+        return Standard_False;
+      }
     }
   }
 
@@ -535,8 +553,26 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
                                                  const Standard_Integer theDepthFormat,
                                                  const unsigned int     theColorRBufferFromWindow)
 {
-  myColorFormats.Clear();
-  myColorFormats.Append (theColorFormat);
+  OpenGl_ColorFormats aColorFormats;
+  if (theColorFormat != 0)
+  {
+    aColorFormats.Append (theColorFormat);
+  }
+  return initRenderBuffer (theGlCtx, theSize, aColorFormats, theDepthFormat, 0, theColorRBufferFromWindow);
+}
+
+// =======================================================================
+// function : initRenderBuffer
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::initRenderBuffer (const Handle(OpenGl_Context)& theGlCtx,
+                                                       const Graphic3d_Vec2i& theSize,
+                                                       const OpenGl_ColorFormats& theColorFormats,
+                                                       const Standard_Integer theDepthFormat,
+                                                       const Standard_Integer theNbSamples,
+                                                       const unsigned int     theColorRBufferFromWindow)
+{
+  myColorFormats = theColorFormats;
   if (!myColorTextures.IsEmpty())
   {
     Handle(OpenGl_Texture) aTexutre = myColorTextures.First();
@@ -549,7 +585,7 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
   }
 
   myDepthFormat = theDepthFormat;
-  myNbSamples   = 0;
+  myNbSamples   = theNbSamples;
   myInitVPSizeX = theSize.x();
   myInitVPSizeY = theSize.y();
   if (theGlCtx->arbFBO == NULL)
@@ -559,6 +595,14 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
 
   // clean up previous state
   Release (theGlCtx.operator->());
+  if (theNbSamples > theGlCtx->MaxMsaaSamples()
+   || theNbSamples < 0)
+  {
+    theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                           TCollection_AsciiString ("Error: FBO creation failed - MSAA") + theNbSamples
+                           + " render buffer exceeds samples limit: " + theGlCtx->MaxMsaaSamples() + ").");
+    return Standard_False;
+  }
 
   myIsOwnColor  = true;
   myIsOwnBuffer = true;
@@ -575,11 +619,43 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
   {
     myGlColorRBufferId = theColorRBufferFromWindow;
   }
-  else if (theColorFormat != 0)
+  else if (!theColorFormats.IsEmpty())
   {
+    if (theColorFormats.Size() != 1)
+    {
+      throw Standard_NotImplemented ("Multiple color attachments as FBO render buffers are not implemented");
+    }
+
+    const GLint aColorFormat = theColorFormats.First();
+    const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theGlCtx, aColorFormat);
+    if (!aFormat.IsValid())
+    {
+      Release (theGlCtx.operator->());
+      return Standard_False;
+    }
+
     theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
-    theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, theColorFormat, aSizeX, aSizeY);
+    if (theNbSamples != 0)
+    {
+      theGlCtx->Functions()->glRenderbufferStorageMultisample (GL_RENDERBUFFER, theNbSamples, aFormat.InternalFormat(), aSizeX, aSizeY);
+    }
+    else
+    {
+      theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, aFormat.InternalFormat(), aSizeX, aSizeY);
+    }
+    theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+
+    const GLenum aRendImgErr = theGlCtx->core11fwd->glGetError();
+    if (aRendImgErr != GL_NO_ERROR)
+    {
+      theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                             TCollection_AsciiString ("Error: FBO color render buffer ") + aSizeX + "x" + aSizeY + "@" + theNbSamples
+                             + " IF: " + OpenGl_TextureFormat::FormatFormat (aFormat.InternalFormat())
+                             + " can not be created with error " + OpenGl_Context::FormatGlError (aRendImgErr) + ".");
+      Release (theGlCtx.get());
+      return Standard_False;
+    }
   }
 
   bool hasStencilRB = false;
@@ -590,15 +666,36 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
 
     theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
-    theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
+    if (theNbSamples != 0)
+    {
+      theGlCtx->Functions()->glRenderbufferStorageMultisample (GL_RENDERBUFFER, theNbSamples, myDepthFormat, aSizeX, aSizeY);
+    }
+    else
+    {
+      theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
+    }
     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+
+    const GLenum aRendImgErr = theGlCtx->core11fwd->glGetError();
+    if (aRendImgErr != GL_NO_ERROR)
+    {
+      theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                             TCollection_AsciiString ("Error: FBO depth render buffer ") + aSizeX + "x" + aSizeY + "@" + theNbSamples
+                             + " IF: " + OpenGl_TextureFormat::FormatFormat (myDepthFormat)
+                             + " can not be created with error " + OpenGl_Context::FormatGlError (aRendImgErr) + ".");
+      Release (theGlCtx.get());
+      return Standard_False;
+    }
   }
 
   // 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 (myGlColorRBufferId != NO_RENDERBUFFER)
+  {
+    theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                                 GL_RENDERBUFFER, myGlColorRBufferId);
+  }
   if (myGlDepthRBufferId != NO_RENDERBUFFER)
   {
     if (hasDepthStencilAttach (theGlCtx) && hasStencilRB)
index ca34f1a7a693b57d717f8c2f60e8921dc8bb76c9..3071c04cdc30e83edeb3d584d2dc91b25db3adfb 100644 (file)
@@ -165,9 +165,26 @@ public:
 
   //! (Re-)initialize FBO with properties taken from another FBO.
   Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx,
-                             const OpenGl_FrameBuffer&     theFbo)
+                             const OpenGl_FrameBuffer& theFbo,
+                             const Standard_Boolean theToKeepMsaa = true)
   {
-    return InitLazy (theGlCtx, Graphic3d_Vec2i (theFbo.myVPSizeX, theFbo.myVPSizeY), theFbo.myColorFormats, theFbo.myDepthFormat, theFbo.myNbSamples);
+    return InitLazy (theGlCtx, Graphic3d_Vec2i (theFbo.myVPSizeX, theFbo.myVPSizeY), theFbo.myColorFormats, theFbo.myDepthFormat, theToKeepMsaa ? theFbo.myNbSamples : 0);
+  }
+
+  //! (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 theSize         render buffer width x height
+  //! @param theColorFormats list of color render buffer sized format, e.g. GL_RGBA8; list should define only one element
+  //! @param theDepthFormat  depth-stencil render buffer sized format, e.g. GL_DEPTH24_STENCIL8
+  //! @param theNbSamples    MSAA number of samples (0 means normal render buffer)
+  Standard_Boolean InitRenderBuffer (const Handle(OpenGl_Context)& theGlCtx,
+                                     const Graphic3d_Vec2i& theSize,
+                                     const OpenGl_ColorFormats& theColorFormats,
+                                     const Standard_Integer theDepthFormat,
+                                     const Standard_Integer theNbSamples = 0)
+  {
+    return initRenderBuffer (theGlCtx, theSize, theColorFormats, theDepthFormat, theNbSamples, 0);
   }
 
   //! (Re-)initialize FBO with specified dimensions.
@@ -176,12 +193,12 @@ public:
   //! @param theSize        render buffer width x 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
+  //! @param theColorRBufferFromWindow 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 Graphic3d_Vec2i& theSize,
                                                const Standard_Integer theColorFormat,
                                                const Standard_Integer theDepthFormat,
-                                               const unsigned int     theColorRBufferFromWindow = 0);
+                                               const unsigned int     theColorRBufferFromWindow);
 
   //! Initialize class from currently bound FBO.
   //! Retrieved OpenGL objects will not be destroyed on Release.
@@ -220,9 +237,15 @@ public:
   //! Returns the depth-stencil texture.
   const Handle(OpenGl_Texture)& DepthStencilTexture() const { return myDepthStencilTexture; }
 
+  //! Returns TRUE if color Render Buffer is defined.
+  bool IsColorRenderBuffer() const { return myGlColorRBufferId != NO_RENDERBUFFER; }
+
   //! Returns the color Render Buffer.
   unsigned int ColorRenderBuffer() const { return myGlColorRBufferId; }
 
+  //! Returns TRUE if depth Render Buffer is defined.
+  bool IsDepthStencilRenderBuffer() const { return myGlDepthRBufferId != NO_RENDERBUFFER; }
+
   //! Returns the depth Render Buffer.
   unsigned int DepthStencilRenderBuffer() const { return myGlDepthRBufferId; }
 
@@ -231,6 +254,21 @@ public:
 
 public:
 
+  //! (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 theSize         render buffer width x height
+  //! @param theColorFormats list of color render buffer sized format, e.g. GL_RGBA8
+  //! @param theDepthFormat  depth-stencil render buffer sized format, e.g. GL_DEPTH24_STENCIL8
+  //! @param theNbSamples    MSAA number of samples (0 means normal render buffer)
+  //! @param theColorRBufferFromWindow when specified - should be ID of already initialized RB object, which will be released within this class
+  Standard_EXPORT Standard_Boolean initRenderBuffer (const Handle(OpenGl_Context)& theGlCtx,
+                                                     const Graphic3d_Vec2i& theSize,
+                                                     const OpenGl_ColorFormats& theColorFormats,
+                                                     const Standard_Integer theDepthFormat,
+                                                     const Standard_Integer theNbSamples,
+                                                     const unsigned int     theColorRBufferFromWindow);
+
   //! Initialize FBO for rendering into single/multiple color buffer and depth textures.
   Standard_DEPRECATED("Obsolete method, use Init() taking Graphic3d_Vec2i")
   bool Init (const Handle(OpenGl_Context)& theGlCtx,
index 759a12fe3f399e0da9b8c88245a10a9b7bd7e87b..1d1933ff23cebddb11b5b49c9ac1ff43b6ffd702 100644 (file)
@@ -712,9 +712,12 @@ bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
                                         const Standard_Integer theSizeY)
 {
   if (!Create (theCtx)
-    || theNbSamples > theCtx->MaxMsaaSamples()
-    || theNbSamples < 1)
+   ||  theNbSamples > theCtx->MaxMsaaSamples()
+   ||  theNbSamples < 1)
   {
+    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         TCollection_AsciiString ("Error: MSAA texture ") + theSizeX + "x" + theSizeY + "@" + myNbSamples
+                         + " exceeds samples limit: " + theCtx->MaxMsaaSamples() + ".");
     return false;
   }
 
@@ -724,26 +727,42 @@ bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
   if(theSizeX > theCtx->MaxTextureSize()
   || theSizeY > theCtx->MaxTextureSize())
   {
+    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         TCollection_AsciiString ("Error: MSAA texture ") + theSizeX + "x" + theSizeY + "@" + myNbSamples
+                         + " exceeds size limit: " + theCtx->MaxTextureSize() + "x" + theCtx->MaxTextureSize() + ".");
     return false;
   }
 
   Bind (theCtx);
   //myTextFormat = theTextFormat;
   mySizedFormat = theTextFormat;
-#if !defined(GL_ES_VERSION_2_0)
-  if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
+  if (theCtx->HasTextureMultisampling()
+   && theCtx->Functions()->glTexStorage2DMultisample != NULL)
   {
     theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
   }
-  else
+#if !defined(GL_ES_VERSION_2_0)
+  else if (theCtx->HasTextureMultisampling()
+        && theCtx->Functions()->glTexImage2DMultisample != NULL)
   {
     theCtx->Functions()->glTexImage2DMultisample   (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
   }
-#else
-  theCtx->Functions()  ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
 #endif
-  if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
+  else
   {
+    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         "Error: MSAA textures are not supported by hardware.");
+    Unbind (theCtx);
+    return false;
+  }
+
+  const GLenum aTexImgErr = theCtx->core11fwd->glGetError();
+  if (aTexImgErr != GL_NO_ERROR)
+  {
+    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         TCollection_AsciiString ("Error: MSAA texture ") + theSizeX + "x" + theSizeY + "@" + myNbSamples
+                         + " IF: " + OpenGl_TextureFormat::FormatFormat (theTextFormat)
+                         + " cannot be created with error " + OpenGl_Context::FormatGlError (aTexImgErr) + ".");
     Unbind (theCtx);
     return false;
   }
index a2d17ad6a547b0b5cc56eb08b7fbdde8b173760c..c636f9252b84bb502bb02217c135016c9f1b5cee 100644 (file)
@@ -1106,6 +1106,11 @@ bool OpenGl_View::prepareFrameBuffers (Graphic3d_Camera::Projection& theProj)
   {
     aNbSamples = OpenGl_Context::GetPowerOfTwo (aNbSamples, aCtx->MaxMsaaSamples());
   }
+  // Only MSAA textures can be blit into MSAA target,
+  // while render buffers could be resolved only into non-MSAA targets.
+  // As result, within obsolete OpenGL ES 3.0 context, we may create only one MSAA render buffer for main scene content
+  // and blit it into non-MSAA immediate FBO.
+  const bool hasTextureMsaa = aCtx->HasTextureMultisampling();
 
   bool toUseOit = myRenderParams.TransparencyMethod != Graphic3d_RTM_BLEND_UNORDERED
                && checkOitCompatibility (aCtx, aNbSamples > 0);
@@ -1156,7 +1161,7 @@ bool OpenGl_View::prepareFrameBuffers (Graphic3d_Camera::Projection& theProj)
     if (myMainSceneFbos[0]->IsValid() && (toInitImmediateFbo || myImmediateSceneFbos[0]->IsValid()))
     {
       const bool wasFailedImm0 = checkWasFailedFbo (myImmediateSceneFbos[0], myMainSceneFbos[0]);
-      if (!myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0])
+      if (!myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0], hasTextureMsaa)
        && !wasFailedImm0)
       {
         TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! Immediate FBO "
@@ -1200,7 +1205,7 @@ bool OpenGl_View::prepareFrameBuffers (Graphic3d_Camera::Projection& theProj)
         && myMainSceneFbos[0]->IsValid())
   {
     const bool wasFailedMain1 = checkWasFailedFbo (myMainSceneFbos[1], myMainSceneFbos[0]);
-    if (!myMainSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0])
+    if (!myMainSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0], true)
      && !wasFailedMain1)
     {
       TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! Main FBO (second) "
@@ -1221,14 +1226,14 @@ bool OpenGl_View::prepareFrameBuffers (Graphic3d_Camera::Projection& theProj)
     {
       const bool wasFailedImm0 = checkWasFailedFbo (myImmediateSceneFbos[0], myMainSceneFbos[0]);
       const bool wasFailedImm1 = checkWasFailedFbo (myImmediateSceneFbos[1], myMainSceneFbos[0]);
-      if (!myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0])
+      if (!myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0], hasTextureMsaa)
        && !wasFailedImm0)
       {
         TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! Immediate FBO (first) "
                                         + printFboFormat (myImmediateSceneFbos[0]) + " initialization has failed";
         aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
       }
-      if (!myImmediateSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0])
+      if (!myImmediateSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0], hasTextureMsaa)
        && !wasFailedImm1)
       {
         TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! Immediate FBO (first) "
@@ -2649,9 +2654,22 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
   aCtx->SetColorMask (true); // restore default alpha component write state
 
   const bool toApplyGamma = aCtx->ToRenderSRGB() != aCtx->IsFrameBufferSRGB();
-  if (aCtx->arbFBOBlit != NULL
-  && !toApplyGamma
-  &&  theReadFbo->NbSamples() != 0)
+  bool toDrawTexture = true;
+  if (aCtx->arbFBOBlit != NULL)
+  {
+    if (!toApplyGamma
+     &&  theReadFbo->NbSamples() != 0)
+    {
+      toDrawTexture = false;
+    }
+    if (theReadFbo->IsColorRenderBuffer())
+    {
+      // render buffers could be resolved only via glBlitFramebuffer()
+      toDrawTexture = false;
+    }
+  }
+
+  if (!toDrawTexture)
   {
     GLbitfield aCopyMask = 0;
     theReadFbo->BindReadBuffer (aCtx);
index f722dfdc53bec3cc2c2d5af20b75e020e0b9a9d8..89140cdea79bbbd8aaea0e4610d40e63b2d7ea43 100644 (file)
@@ -785,7 +785,9 @@ void OpenGl_Window::Init()
       aDefFbo = new OpenGl_FrameBuffer();
     }
 
-    if (!aDefFbo->InitWithRB (myGlContext, Graphic3d_Vec2i (myWidth, myHeight), GL_RGBA8, GL_DEPTH24_STENCIL8))
+    OpenGl_ColorFormats aColorFormats;
+    aColorFormats.Append (GL_RGBA8);
+    if (!aDefFbo->InitRenderBuffer (myGlContext, Graphic3d_Vec2i (myWidth, myHeight), aColorFormats, GL_DEPTH24_STENCIL8))
     {
       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO creation failed");
       throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());