From c8365a1c280fcbed1a89a6b6027a26e9f81f49ff Mon Sep 17 00:00:00 2001 From: kgv Date: Tue, 2 Nov 2021 16:23:25 +0300 Subject: [PATCH] 0032648: Visualization, TKOpenGles - support MSAA anti-aliasing within WebGL 2.0 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 | 8 +-- src/OpenGl/OpenGl_Context.cxx | 52 ++++++++++++-- src/OpenGl/OpenGl_Context.hxx | 47 +++++-------- src/OpenGl/OpenGl_FrameBuffer.cxx | 113 +++++++++++++++++++++++++++--- src/OpenGl/OpenGl_FrameBuffer.hxx | 46 ++++++++++-- src/OpenGl/OpenGl_Texture.cxx | 35 ++++++--- src/OpenGl/OpenGl_View.cxx | 32 +++++++-- src/OpenGl/OpenGl_Window.cxx | 4 +- 8 files changed, 268 insertions(+), 69 deletions(-) diff --git a/adm/templates/env.bat.in b/adm/templates/env.bat.in index 94e8db5cea..538ad7cc67 100644 --- a/adm/templates/env.bat.in +++ b/adm/templates/env.bat.in @@ -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%" == "" ( diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index 38c27c2015..da868a036c 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -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 : diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx index 27849d3169..e0cf8cdf1e 100644 --- a/src/OpenGl/OpenGl_Context.hxx +++ b/src/OpenGl/OpenGl_Context.hxx @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -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 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 diff --git a/src/OpenGl/OpenGl_FrameBuffer.cxx b/src/OpenGl/OpenGl_FrameBuffer.cxx index 1864da9a4f..6ee169946a 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.cxx +++ b/src/OpenGl/OpenGl_FrameBuffer.cxx @@ -19,6 +19,7 @@ #include #include +#include #include 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) diff --git a/src/OpenGl/OpenGl_FrameBuffer.hxx b/src/OpenGl/OpenGl_FrameBuffer.hxx index ca34f1a7a6..3071c04cdc 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.hxx +++ b/src/OpenGl/OpenGl_FrameBuffer.hxx @@ -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, diff --git a/src/OpenGl/OpenGl_Texture.cxx b/src/OpenGl/OpenGl_Texture.cxx index 759a12fe3f..1d1933ff23 100644 --- a/src/OpenGl/OpenGl_Texture.cxx +++ b/src/OpenGl/OpenGl_Texture.cxx @@ -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; } diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx index a2d17ad6a5..c636f9252b 100644 --- a/src/OpenGl/OpenGl_View.cxx +++ b/src/OpenGl/OpenGl_View.cxx @@ -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); diff --git a/src/OpenGl/OpenGl_Window.cxx b/src/OpenGl/OpenGl_Window.cxx index f722dfdc53..89140cdea7 100644 --- a/src/OpenGl/OpenGl_Window.cxx +++ b/src/OpenGl/OpenGl_Window.cxx @@ -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());