From 3c4b62a436d2247552e746791bfc9a8e5510b8fd Mon Sep 17 00:00:00 2001 From: kgv Date: Wed, 21 Oct 2015 19:06:02 +0300 Subject: [PATCH] 0026711: Visualization, TKOpenGl - support creation of multisampling off-screen FBOs 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. --- src/Graphic3d/Graphic3d_RenderingParams.hxx | 5 +- src/OpenGl/OpenGl_Context.cxx | 92 ++++++--- src/OpenGl/OpenGl_Context.hxx | 12 +- src/OpenGl/OpenGl_FrameBuffer.cxx | 202 ++++++++++++++----- src/OpenGl/OpenGl_FrameBuffer.hxx | 73 +++++-- src/OpenGl/OpenGl_GlFunctions.hxx | 14 ++ src/OpenGl/OpenGl_Texture.cxx | 54 ++++- src/OpenGl/OpenGl_Texture.hxx | 7 + src/OpenGl/OpenGl_View.cxx | 11 + src/OpenGl/OpenGl_View.hxx | 5 +- src/OpenGl/OpenGl_View_Print.cxx | 2 +- src/OpenGl/OpenGl_View_Raytrace.cxx | 37 +--- src/OpenGl/OpenGl_View_Redraw.cxx | 104 +++++++--- src/OpenGl/OpenGl_Window_1.mm | 2 +- src/OpenGl/OpenGl_Workspace.cxx | 2 +- src/ViewerTest/ViewerTest_ViewerCommands.cxx | 30 ++- tests/v3d/glsl/msaa | 24 +++ 17 files changed, 508 insertions(+), 168 deletions(-) create mode 100644 tests/v3d/glsl/msaa diff --git a/src/Graphic3d/Graphic3d_RenderingParams.hxx b/src/Graphic3d/Graphic3d_RenderingParams.hxx index b57421382f..c9330902be 100644 --- a/src/Graphic3d/Graphic3d_RenderingParams.hxx +++ b/src/Graphic3d/Graphic3d_RenderingParams.hxx @@ -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) diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index 2a960a2d87..52b4f22a9b 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -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) { diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx index 074f467e5d..163265dcbe 100644 --- a/src/OpenGl/OpenGl_Context.hxx +++ b/src/OpenGl/OpenGl_Context.hxx @@ -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 diff --git a/src/OpenGl/OpenGl_FrameBuffer.cxx b/src/OpenGl/OpenGl_FrameBuffer.cxx index 38cb43fd06..caf82a2eda 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.cxx +++ b/src/OpenGl/OpenGl_FrameBuffer.cxx @@ -18,15 +18,62 @@ #include #include +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); + if (myColorFormat != 0 + && !myColorTexture->Init (theGlContext, myColorFormat, + GL_RGBA, GL_UNSIGNED_BYTE, + aSizeX, aSizeY, Graphic3d_TOT_2D)) + { + Release (theGlContext.operator->()); + return Standard_False; + } - 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); + // 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; diff --git a/src/OpenGl/OpenGl_FrameBuffer.hxx b/src/OpenGl/OpenGl_FrameBuffer.hxx index 0fceeaf989..6c907b0211 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.hxx +++ b/src/OpenGl/OpenGl_FrameBuffer.hxx @@ -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) diff --git a/src/OpenGl/OpenGl_GlFunctions.hxx b/src/OpenGl/OpenGl_GlFunctions.hxx index d75d686ca7..50a1116a15 100644 --- a/src/OpenGl/OpenGl_GlFunctions.hxx +++ b/src/OpenGl/OpenGl_GlFunctions.hxx @@ -62,6 +62,10 @@ // 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 @@ -104,6 +108,11 @@ #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 diff --git a/src/OpenGl/OpenGl_Texture.cxx b/src/OpenGl/OpenGl_Texture.cxx index dde0ff748a..256a989d6c 100644 --- a/src/OpenGl/OpenGl_Texture.cxx +++ b/src/OpenGl/OpenGl_Texture.cxx @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include @@ -660,6 +660,58 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, theType, &theImage); } +// ======================================================================= +// 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 : diff --git a/src/OpenGl/OpenGl_Texture.hxx b/src/OpenGl/OpenGl_Texture.hxx index 1a1a0ed955..06905e9bac 100644 --- a/src/OpenGl/OpenGl_Texture.hxx +++ b/src/OpenGl/OpenGl_Texture.hxx @@ -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, diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx index b5723967d7..6ecb61dff5 100644 --- a/src/OpenGl/OpenGl_View.cxx +++ b/src/OpenGl/OpenGl_View.cxx @@ -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->()); diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index b256b4e759..c52b86c777 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -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; diff --git a/src/OpenGl/OpenGl_View_Print.cxx b/src/OpenGl/OpenGl_View_Print.cxx index 93b9db1cdb..5f53f44667 100644 --- a/src/OpenGl/OpenGl_View_Print.cxx +++ b/src/OpenGl/OpenGl_View_Print.cxx @@ -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 diff --git a/src/OpenGl/OpenGl_View_Raytrace.cxx b/src/OpenGl/OpenGl_View_Raytrace.cxx index 27e9b007c1..c0eacbb8b3 100644 --- a/src/OpenGl/OpenGl_View_Raytrace.cxx +++ b/src/OpenGl/OpenGl_View_Raytrace.cxx @@ -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 { diff --git a/src/OpenGl/OpenGl_View_Redraw.cxx b/src/OpenGl/OpenGl_View_Redraw.cxx index 5fb382dc9d..542360e2d7 100644 --- a/src/OpenGl/OpenGl_View_Redraw.cxx +++ b/src/OpenGl/OpenGl_View_Redraw.cxx @@ -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); diff --git a/src/OpenGl/OpenGl_Window_1.mm b/src/OpenGl/OpenGl_Window_1.mm index 2e85cca3e2..fc3dc6ca96 100644 --- a/src/OpenGl/OpenGl_Window_1.mm +++ b/src/OpenGl/OpenGl_Window_1.mm @@ -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()); diff --git a/src/OpenGl/OpenGl_Workspace.cxx b/src/OpenGl/OpenGl_Workspace.cxx index ede088caae..03f3ba49fd 100644 --- a/src/OpenGl/OpenGl_Workspace.cxx +++ b/src/OpenGl/OpenGl_Workspace.cxx @@ -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; diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 6e92634757..9642900302 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -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 index 0000000000..6885beec3b --- /dev/null +++ b/tests/v3d/glsl/msaa @@ -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