wxWidgets / Phoenix

wxPython's Project Phoenix. A new implementation of wxPython, better, stronger, faster than he was before.
http://wxpython.org/
2.21k stars 509 forks source link

wxPython (4.2.0) reports an OpenGL context error shipping with moderngl/glcontext #2517

Closed haochenscut closed 3 months ago

haochenscut commented 3 months ago

Brief introduction

My MWE encountered an OpenGL context problem when upgrading from wxPython == 4.1.0 (works well) to 4.2.0 (failed).

OS: Ubuntu 20.04 GCC: 9.4.0 Python: 3.8.10

moderngl: 5.9.0 glcontext: 2.3.7

wxPython Install from:

python3 -m pip install wxPython==4.1.0

or

python3 -m pip install wxPython .

moderngl and glcontext are built from source code:

python3 -m pip install -e .

MWE

import wx
import wx.glcanvas as glcanvas
import moderngl

class mcanvas(glcanvas.GLCanvas):
    def __init__(self, parent):
        attribList = attribs = (glcanvas.WX_GL_CORE_PROFILE, glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 24)
        glcanvas.GLCanvas.__init__(self, parent, -1, attribList=attribList)
        self.context = glcanvas.GLContext(self)
        self.ctx = None
        self.SetBackgroundStyle(wx.BG_STYLE_PAINT)

        self.init = False

        self.Bind(wx.EVT_PAINT, self.OnPaint)

    def OnPaint(self, event):
        dc = wx.PaintDC(self)
        self.SetCurrent(self.context)

        if not self.init:
            self.ctx = moderngl.create_context()
            self.init=True

        self.ctx.clear(0.1, 0.2, 0.3)
        self.SwapBuffers()

class mframe (wx.Frame):
    def __init__( self, parent):
        wx.Frame.__init__ ( self, parent, size = wx.Size( 300,300 ), style = wx.DEFAULT_FRAME_STYLE)
        self.canvas = mcanvas(self)

class mapp(wx.App):
    def __init__(self):
        wx.App.__init__(self)

    def OnInit(self):
        self.frame = mframe(None)
        self.frame.Show()
        return True

app = mapp()
app.MainLoop()

Error

Traceback (most recent call last):

    self.ctx = moderngl.create_context()

    ctx.mglo, ctx.version_code = mgl.create_context(glversion=require, mode=mode, **settings)

    return x11.create_context(**kwargs)

Exception: (detect) glXGetCurrentContext: cannot detect OpenGL context

Discussion

I observed the different behaviour in glcontext/x11.cpp :

res->m_glXGetCurrentContext = (m_glXGetCurrentContextProc)dlsym(res->libgl, "glXGetCurrentContext");

and

res->ctx = res->m_glXGetCurrentContext(); // Failed in glcontext with wxPython 4.2.0

The OpenGL context-related symbols glXGetCurrentContext in libGL did not work as expected in wxPython 4.2.0.

As far as I know, the wx.glcanvas may serve to communicate between wx and OpenGL.

I would appreciate it if you may explain if there are my incorrect settings or the possible bug of wx.glcanvas ?

Thank you for your time!

swt2c commented 3 months ago

This is a tricky one. It is possible that wxPython (really wxWidgets) was built in your environment with EGL support and not GLX.

Can you try using moderngl's EGL backend instead and see what happens? ctx = moderngl.create_context(backend='egl')

haochenscut commented 3 months ago

Thank you for your reply!

  1. Response from backend='egl':
Traceback (most recent call last):

  File "test.py", line 25, in OnPaint

    self.ctx = moderngl.create_context(backend='egl')

  File "moderngl/__init__.py", line 1931, in create_context

    ctx.mglo, ctx.version_code = mgl.create_context(glversion=require, mode=mode, **settings)

  File "glcontext/__init__.py", line 120, in create

    return egl.create_context(**kwargs)

Exception: unknown mode

More trial

After this post, I download the source code Tag = 4.2.0 and Tag = 4.1.0 and master and built them myself:

git clone xxx
git submodule update --init --recursive

Then,

git checkout -b v410(v420) SHAs
git checkout -b wxwidget SHAa  // based on the SHA on each wxPython

Built by

python3 build.py dox etg sip build

Build results

  1. Master:

Build pass, but when I run the MWE, an error is reported like the version of EGL should be 1.5 or higher.

I believe that is what you mentioned as wxWidget binded against EGL instead of GLX.

  1. Tag 4.2.0

Build pass, and the error of cannot detect OpenGL context was there.

  1. Tag 4.1.0

Both of build and run worked well.

EGL vs GLX

I noticed that there is an option in wxwidget as --disable-canvasegl, and I set it in the wxpython build.py::cmd_build_wx function, but an error of no such an option as --disable-canvasegl appeared.

Up to now, I have been confused by the switch between EGL and GLX and suspect the reason for the crashed MWE to the incorrect build or run settings.

Moreover, the comparison between the sip files of ``sip_glcanvaswxGLContext``` on version 4.2.0 and 4.1.0 does not indicate too much difference.

But the sip_glcanvaswxGLCanvas may reveal some cxx cast for wx pyobjects and additional APIs of either wxwidget or wxpython.

Thank you so much if you could help me clarify if the EGL/GLX really matters.

Or if there are some new features about OpenGL context on 4.2.0 added and missed by my case!

Thank you for your time!

haochenscut commented 3 months ago

I found a possible workaround for the moderngl OpenGL context error on wxPython >= 4.2.0.

Fix

Hardcode the main(wxDir, args) in build_wxwidgets.py:

configure_opts.append("--disable-glcanvasegl")

Replace the default EGL in wxPython == 4.2.0 by X11, and done.

About moderngl

moderngl supports the EGL but only in headless mode.

Moreover, I am not familiar with how to change the EGL to X11 on runtime, maybe there are some smart detection flags that work for the Python side instead of compile time.

swt2c commented 3 months ago

@haochenscut yes, that is what I was going to recommend but I didn't respond to you in time, sorry. Unfortunately, wxWidgets can only currently be compiled with either GLX or EGL support, but not both at the same time. It probably makes sense for wxPython to recompile it's own copy with GLX support for now (using the workaround you noted).

haochenscut commented 3 months ago

Thank you for your information! I will close this issue now.