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 defined(HAVE_EGL)
|
||||||
if ((EGLDisplay )myDisplay == EGL_NO_DISPLAY
|
if ((EGLDisplay )myDisplay == EGL_NO_DISPLAY
|
||||||
|| (EGLSurface )myWindow == EGL_NO_SURFACE
|
|
||||||
|| (EGLContext )myGContext == EGL_NO_CONTEXT)
|
|| (EGLContext )myGContext == EGL_NO_CONTEXT)
|
||||||
{
|
{
|
||||||
return Standard_False;
|
return Standard_False;
|
||||||
@@ -580,7 +579,6 @@ Standard_Boolean OpenGl_Context::MakeCurrent()
|
|||||||
{
|
{
|
||||||
#if defined(HAVE_EGL)
|
#if defined(HAVE_EGL)
|
||||||
if ((EGLDisplay )myDisplay == EGL_NO_DISPLAY
|
if ((EGLDisplay )myDisplay == EGL_NO_DISPLAY
|
||||||
|| (EGLSurface )myWindow == EGL_NO_SURFACE
|
|
||||||
|| (EGLContext )myGContext == EGL_NO_CONTEXT)
|
|| (EGLContext )myGContext == EGL_NO_CONTEXT)
|
||||||
{
|
{
|
||||||
Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
|
Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
|
||||||
|
@@ -55,6 +55,45 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_GraphicDriver,Graphic3d_GraphicDriver)
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
static const Handle(OpenGl_Context) TheNullGlCtx;
|
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;
|
return Standard_False;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLint aConfigAttribs[] =
|
myEglConfig = chooseEglSurfConfig ((EGLDisplay )myEglDisplay);
|
||||||
{
|
if (myEglConfig == NULL)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
::Message::DefaultMessenger()->Send ("Error: EGL does not provide compatible configurations!", Message_Fail);
|
::Message::DefaultMessenger()->Send ("Error: EGL does not provide compatible configurations!", Message_Fail);
|
||||||
return Standard_False;
|
return Standard_False;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(GL_ES_VERSION_2_0)
|
#if defined(GL_ES_VERSION_2_0)
|
||||||
EGLint anEglCtxAttribs[] =
|
EGLint anEglCtxAttribs[] =
|
||||||
@@ -384,14 +400,22 @@ Standard_Boolean OpenGl_GraphicDriver::InitEglContext (Aspect_Display t
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((EGLDisplay )theEglDisplay == EGL_NO_DISPLAY
|
if ((EGLDisplay )theEglDisplay == EGL_NO_DISPLAY
|
||||||
|| (EGLContext )theEglContext == EGL_NO_CONTEXT
|
|| (EGLContext )theEglContext == EGL_NO_CONTEXT)
|
||||||
|| theEglConfig == NULL)
|
|
||||||
{
|
{
|
||||||
return Standard_False;
|
return Standard_False;
|
||||||
}
|
}
|
||||||
myEglDisplay = theEglDisplay;
|
myEglDisplay = theEglDisplay;
|
||||||
myEglContext = theEglContext;
|
myEglContext = theEglContext;
|
||||||
myEglConfig = theEglConfig;
|
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;
|
return Standard_True;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include <OpenGl_Context.hxx>
|
#include <OpenGl_Context.hxx>
|
||||||
#include <OpenGl_GraphicDriver.hxx>
|
#include <OpenGl_GraphicDriver.hxx>
|
||||||
#include <OpenGl_Window.hxx>
|
#include <OpenGl_Window.hxx>
|
||||||
|
#include <OpenGl_FrameBuffer.hxx>
|
||||||
|
|
||||||
#include <Aspect_GraphicDeviceDefinitionError.hxx>
|
#include <Aspect_GraphicDeviceDefinitionError.hxx>
|
||||||
#include <Graphic3d_TransformUtils.hxx>
|
#include <Graphic3d_TransformUtils.hxx>
|
||||||
@@ -181,14 +182,15 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
|
|||||||
EGLConfig anEglConfig = (EGLConfig )theDriver->getRawGlConfig();
|
EGLConfig anEglConfig = (EGLConfig )theDriver->getRawGlConfig();
|
||||||
if (anEglDisplay == EGL_NO_DISPLAY
|
if (anEglDisplay == EGL_NO_DISPLAY
|
||||||
|| anEglContext == EGL_NO_CONTEXT
|
|| anEglContext == EGL_NO_CONTEXT
|
||||||
|| anEglConfig == NULL)
|
|| (anEglConfig == NULL
|
||||||
|
&& (EGLContext )theGContext == EGL_NO_CONTEXT))
|
||||||
{
|
{
|
||||||
throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL does not provide compatible configurations!");
|
throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL does not provide compatible configurations!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLSurface anEglSurf = EGL_NO_SURFACE;
|
EGLSurface anEglSurf = EGL_NO_SURFACE;
|
||||||
if (theGContext == (EGLContext )EGL_NO_CONTEXT)
|
if ((EGLContext )theGContext == EGL_NO_CONTEXT)
|
||||||
{
|
{
|
||||||
// create new surface
|
// create new surface
|
||||||
anEglSurf = eglCreateWindowSurface (anEglDisplay,
|
anEglSurf = eglCreateWindowSurface (anEglDisplay,
|
||||||
@@ -211,8 +213,24 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
|
|||||||
anEglSurf = eglGetCurrentSurface(EGL_DRAW);
|
anEglSurf = eglGetCurrentSurface(EGL_DRAW);
|
||||||
if (anEglSurf == EGL_NO_SURFACE)
|
if (anEglSurf == EGL_NO_SURFACE)
|
||||||
{
|
{
|
||||||
throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to retrieve current surface!");
|
// window-less EGL context (off-screen)
|
||||||
return;
|
//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;
|
return;
|
||||||
|
|
||||||
#if defined(HAVE_EGL)
|
#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_WIDTH, &myWidth);
|
||||||
eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_HEIGHT, &myHeight);
|
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);
|
myView->SetWindow (theWindow, theContext);
|
||||||
MyViewer->SetViewOn (this);
|
MyViewer->SetViewOn (this);
|
||||||
SetRatio();
|
SetRatio();
|
||||||
|
if (myImmediateUpdate)
|
||||||
|
{
|
||||||
Redraw();
|
Redraw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -412,8 +415,10 @@ void V3d_View::MustBeResized()
|
|||||||
myView->Resized();
|
myView->Resized();
|
||||||
|
|
||||||
SetRatio();
|
SetRatio();
|
||||||
|
if (myImmediateUpdate)
|
||||||
|
{
|
||||||
Redraw();
|
Redraw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@@ -152,7 +152,11 @@ void V3d_Viewer::SetViewOn (const Handle(V3d_View)& theView)
|
|||||||
|
|
||||||
theView->SetGrid (myPrivilegedPlane, Grid ());
|
theView->SetGrid (myPrivilegedPlane, Grid ());
|
||||||
theView->SetGridActivity (Grid ()->IsActive ());
|
theView->SetGridActivity (Grid ()->IsActive ());
|
||||||
|
if (theView->SetImmediateUpdate (Standard_False))
|
||||||
|
{
|
||||||
theView->Redraw();
|
theView->Redraw();
|
||||||
|
theView->SetImmediateUpdate (Standard_True);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
Reference in New Issue
Block a user