mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-14 13:30:48 +03:00
0030364: Visualization, TKOpenGl - allow initializing a Surface-less EGL context
OpenGl_Context::MakeCurrent()/OpenGl_Context::IsCurrent() have been modified to NOT fail in case if myWindow is EGL_NO_SURFACE (valid off-screen rendering case within EGL). OpenGl_GraphicDriver::InitEglContext() now finds EGL surface config in case if it has not been passed by argument. OpenGl_Window constructor now allows wrapping an off-screen rendering surface EGL_NO_SURFACE. However, it still creates a dummy surface eglCreatePbufferSurface() to workaround bugs in some GLES drivers (Vivante GC2000). V3d_View::SetWindow()/V3d_View::MustBeResized()/V3d_Viewer::SetViewOn() have been modified to avoid implicit View redraw (leading to undefined behavior/crashes in case if rendering should be done into default FBO defined right after V3d_View initialization).
This commit is contained in:
@@ -544,7 +544,6 @@ Standard_Boolean OpenGl_Context::IsCurrent() const
|
||||
{
|
||||
#if defined(HAVE_EGL)
|
||||
if ((EGLDisplay )myDisplay == EGL_NO_DISPLAY
|
||||
|| (EGLSurface )myWindow == EGL_NO_SURFACE
|
||||
|| (EGLContext )myGContext == EGL_NO_CONTEXT)
|
||||
{
|
||||
return Standard_False;
|
||||
@@ -580,7 +579,6 @@ Standard_Boolean OpenGl_Context::MakeCurrent()
|
||||
{
|
||||
#if defined(HAVE_EGL)
|
||||
if ((EGLDisplay )myDisplay == EGL_NO_DISPLAY
|
||||
|| (EGLSurface )myWindow == EGL_NO_SURFACE
|
||||
|| (EGLContext )myGContext == EGL_NO_CONTEXT)
|
||||
{
|
||||
Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
|
||||
|
@@ -55,6 +55,45 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_GraphicDriver,Graphic3d_GraphicDriver)
|
||||
namespace
|
||||
{
|
||||
static const Handle(OpenGl_Context) TheNullGlCtx;
|
||||
|
||||
#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
|
||||
//! Wrapper over eglChooseConfig() called with preferred defaults.
|
||||
static EGLConfig chooseEglSurfConfig (EGLDisplay theDisplay)
|
||||
{
|
||||
EGLint aConfigAttribs[] =
|
||||
{
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 0,
|
||||
EGL_DEPTH_SIZE, 24,
|
||||
EGL_STENCIL_SIZE, 8,
|
||||
#if defined(GL_ES_VERSION_2_0)
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
#else
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
||||
#endif
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLConfig aCfg = NULL;
|
||||
EGLint aNbConfigs = 0;
|
||||
if (eglChooseConfig (theDisplay, aConfigAttribs, &aCfg, 1, &aNbConfigs) == EGL_TRUE
|
||||
|| aCfg != NULL)
|
||||
{
|
||||
return aCfg;
|
||||
}
|
||||
|
||||
eglGetError();
|
||||
aConfigAttribs[4 * 2 + 1] = 16; // try config with smaller depth buffer
|
||||
if (eglChooseConfig (theDisplay, aConfigAttribs, &aCfg, 1, &aNbConfigs) != EGL_TRUE
|
||||
|| aCfg == NULL)
|
||||
{
|
||||
eglGetError();
|
||||
}
|
||||
return aCfg;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
@@ -299,35 +338,12 @@ Standard_Boolean OpenGl_GraphicDriver::InitContext()
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
EGLint aConfigAttribs[] =
|
||||
{
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 0,
|
||||
EGL_DEPTH_SIZE, 24,
|
||||
EGL_STENCIL_SIZE, 8,
|
||||
#if defined(GL_ES_VERSION_2_0)
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
#else
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
||||
#endif
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLint aNbConfigs = 0;
|
||||
if (eglChooseConfig ((EGLDisplay )myEglDisplay, aConfigAttribs, &myEglConfig, 1, &aNbConfigs) != EGL_TRUE
|
||||
|| myEglConfig == NULL)
|
||||
{
|
||||
eglGetError();
|
||||
aConfigAttribs[4 * 2 + 1] = 16; // try config with smaller depth buffer
|
||||
if (eglChooseConfig ((EGLDisplay )myEglDisplay, aConfigAttribs, &myEglConfig, 1, &aNbConfigs) != EGL_TRUE
|
||||
|| myEglConfig == NULL)
|
||||
myEglConfig = chooseEglSurfConfig ((EGLDisplay )myEglDisplay);
|
||||
if (myEglConfig == NULL)
|
||||
{
|
||||
::Message::DefaultMessenger()->Send ("Error: EGL does not provide compatible configurations!", Message_Fail);
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GL_ES_VERSION_2_0)
|
||||
EGLint anEglCtxAttribs[] =
|
||||
@@ -384,14 +400,22 @@ Standard_Boolean OpenGl_GraphicDriver::InitEglContext (Aspect_Display t
|
||||
#endif
|
||||
|
||||
if ((EGLDisplay )theEglDisplay == EGL_NO_DISPLAY
|
||||
|| (EGLContext )theEglContext == EGL_NO_CONTEXT
|
||||
|| theEglConfig == NULL)
|
||||
|| (EGLContext )theEglContext == EGL_NO_CONTEXT)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
myEglDisplay = theEglDisplay;
|
||||
myEglContext = theEglContext;
|
||||
myEglConfig = theEglConfig;
|
||||
if (theEglConfig == NULL)
|
||||
{
|
||||
myEglConfig = chooseEglSurfConfig ((EGLDisplay )myEglDisplay);
|
||||
if (myEglConfig == NULL)
|
||||
{
|
||||
::Message::DefaultMessenger()->Send ("Error: EGL does not provide compatible configurations!", Message_Fail);
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
return Standard_True;
|
||||
}
|
||||
#endif
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <OpenGl_Context.hxx>
|
||||
#include <OpenGl_GraphicDriver.hxx>
|
||||
#include <OpenGl_Window.hxx>
|
||||
#include <OpenGl_FrameBuffer.hxx>
|
||||
|
||||
#include <Aspect_GraphicDeviceDefinitionError.hxx>
|
||||
#include <Graphic3d_TransformUtils.hxx>
|
||||
@@ -181,14 +182,15 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
|
||||
EGLConfig anEglConfig = (EGLConfig )theDriver->getRawGlConfig();
|
||||
if (anEglDisplay == EGL_NO_DISPLAY
|
||||
|| anEglContext == EGL_NO_CONTEXT
|
||||
|| anEglConfig == NULL)
|
||||
|| (anEglConfig == NULL
|
||||
&& (EGLContext )theGContext == EGL_NO_CONTEXT))
|
||||
{
|
||||
throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL does not provide compatible configurations!");
|
||||
return;
|
||||
}
|
||||
|
||||
EGLSurface anEglSurf = EGL_NO_SURFACE;
|
||||
if (theGContext == (EGLContext )EGL_NO_CONTEXT)
|
||||
if ((EGLContext )theGContext == EGL_NO_CONTEXT)
|
||||
{
|
||||
// create new surface
|
||||
anEglSurf = eglCreateWindowSurface (anEglDisplay,
|
||||
@@ -211,8 +213,24 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
|
||||
anEglSurf = eglGetCurrentSurface(EGL_DRAW);
|
||||
if (anEglSurf == EGL_NO_SURFACE)
|
||||
{
|
||||
throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to retrieve current surface!");
|
||||
return;
|
||||
// window-less EGL context (off-screen)
|
||||
//throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to retrieve current surface!");
|
||||
if (anEglConfig != NULL)
|
||||
{
|
||||
const int aSurfAttribs[] =
|
||||
{
|
||||
EGL_WIDTH, myWidth,
|
||||
EGL_HEIGHT, myHeight,
|
||||
EGL_NONE
|
||||
};
|
||||
anEglSurf = eglCreatePbufferSurface (anEglDisplay, anEglConfig, aSurfAttribs);
|
||||
if (anEglSurf == EGL_NO_SURFACE)
|
||||
{
|
||||
throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to create off-screen surface!");
|
||||
}
|
||||
}
|
||||
myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
|
||||
"OpenGl_Window::CreateWindow: WARNING, a Window is created without a EGL Surface!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,7 +733,30 @@ void OpenGl_Window::Init()
|
||||
return;
|
||||
|
||||
#if defined(HAVE_EGL)
|
||||
if (!myPlatformWindow->IsVirtual())
|
||||
if ((EGLSurface )myGlContext->myWindow == EGL_NO_SURFACE)
|
||||
{
|
||||
// define an offscreen default FBO to avoid rendering into EGL_NO_SURFACE;
|
||||
// note that this code is currently never called, since eglCreatePbufferSurface() is used instead as more robust solution
|
||||
// for offscreen rendering on bugged OpenGL ES drivers
|
||||
Handle(OpenGl_FrameBuffer) aDefFbo = myGlContext->SetDefaultFrameBuffer (Handle(OpenGl_FrameBuffer)());
|
||||
if (!aDefFbo.IsNull())
|
||||
{
|
||||
aDefFbo->Release (myGlContext.operator->());
|
||||
}
|
||||
else
|
||||
{
|
||||
aDefFbo = new OpenGl_FrameBuffer();
|
||||
}
|
||||
|
||||
if (!aDefFbo->InitWithRB (myGlContext, myWidth, myHeight, GL_RGBA8, GL_DEPTH24_STENCIL8))
|
||||
{
|
||||
TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO creation failed");
|
||||
throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
|
||||
}
|
||||
myGlContext->SetDefaultFrameBuffer (aDefFbo);
|
||||
aDefFbo->BindBuffer (myGlContext);
|
||||
}
|
||||
else if (!myPlatformWindow->IsVirtual())
|
||||
{
|
||||
eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_WIDTH, &myWidth);
|
||||
eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_HEIGHT, &myHeight);
|
||||
|
@@ -189,7 +189,10 @@ void V3d_View::SetWindow (const Handle(Aspect_Window)& theWindow,
|
||||
myView->SetWindow (theWindow, theContext);
|
||||
MyViewer->SetViewOn (this);
|
||||
SetRatio();
|
||||
if (myImmediateUpdate)
|
||||
{
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@@ -412,8 +415,10 @@ void V3d_View::MustBeResized()
|
||||
myView->Resized();
|
||||
|
||||
SetRatio();
|
||||
|
||||
if (myImmediateUpdate)
|
||||
{
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
@@ -152,7 +152,11 @@ void V3d_Viewer::SetViewOn (const Handle(V3d_View)& theView)
|
||||
|
||||
theView->SetGrid (myPrivilegedPlane, Grid ());
|
||||
theView->SetGridActivity (Grid ()->IsActive ());
|
||||
if (theView->SetImmediateUpdate (Standard_False))
|
||||
{
|
||||
theView->Redraw();
|
||||
theView->SetImmediateUpdate (Standard_True);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
|
Reference in New Issue
Block a user