mcfletch / pyopengl

Repository for the PyOpenGL Project
Other
318 stars 101 forks source link

Regression to access to glInitFramebufferObjectARB in v3.1.6 #88

Open vallsv opened 1 year ago

vallsv commented 1 year ago

Hi,

I have a problem with some of my machine with project using PyOpenGL.

It looks like, with exact same env, the capability glInitFramebufferObjectARB

Do you think it's a regression?

Do you think there is a wrong use on my script?

How can i help you to find the problem?

With 3.1.5

In [1]: import pygame as pg
In [2]: pg.init()
In [3]: import OpenGL.GL
In [5]: from pygame.locals import *
   ...: from OpenGL.GL import *
   ...: from OpenGL.GLU import *
In [6]: pg.display.set_mode((50, 50), DOUBLEBUF|OPENGL)
In [9]: OpenGL.GL.glGetString(OpenGL.GL.GL_VERSION)
Out[9]: b'3.0 Mesa 18.3.6'
In [10]: from OpenGL.GL.ARB.framebuffer_object import glInitFramebufferObjectARB
In [11]: glInitFramebufferObjectARB()
Out[11]: True
In [12]: OpenGL.__version__
Out[12]: '3.1.5'

With 3.1.6

In [1]: import pygame as pg
In [2]: from pygame.locals import *
   ...: from OpenGL.GL import *
   ...: from OpenGL.GLU import *
In [3]: pg.display.set_mode((50, 50), DOUBLEBUF|OPENGL)
In [4]: OpenGL.GL.glGetString(OpenGL.GL.GL_VERSION)
Out[4]: b'3.0 Mesa 18.3.6'
In [5]: from OpenGL.GL.ARB.framebuffer_object import glInitFramebufferObjectARB
In [6]: glInitFramebufferObjectARB()
Out[6]: False
In [7]: OpenGL.__version__
Out[7]: '3.1.6'
vallsv commented 1 year ago

If i launch my application with the env PYOPENGL_PLATFORM=linux it works well.

Here is my env

WAYLAND_DISPLAY=wayland-0
DISPLAY=:0
XDG_SESSION_TYPE=wayland
mcfletch commented 1 year ago

So this seems like a side-effect from enhancing support for wayland. Specifically it looks like the code that checks to see whether we are using wayland is passing (i.e. it says "this is a wayland environment") but pygame is AFAICT using x-wayland to run.

If you try to make pygame use wayland (with SDL_VIDEODRIVER=wayland) it bombs out claiming there's no wayland available (possibly because an underlying library wasn't compiled for wayland). Under the covers what's likely happening here is that the call to isContextValid() is failing because it's checking for an EGL context, and the pygame context is a glX context. The older version, being less "smart" was just saying "oh, this is linux, great, use X" and so ignoring the wayland setup.

Not really sure what the correct solution is here, options:

For instance, this patch "fixes" the immediate issue (but with a huge run-time cost, so not likely to land)

diff --git a/OpenGL/extensions.py b/OpenGL/extensions.py
index d4af5b68..a3e8c408 100644
--- a/OpenGL/extensions.py
+++ b/OpenGL/extensions.py
@@ -193,6 +193,8 @@ class _GLQuerier( ExtensionQuerier ):
             else:
                 break
         return extensions
+
+
 GLQuerier = _GLQuerier()
 class _GLUQuerier( ExtensionQuerier ):
     prefix = as_8_bit('GLU_')
diff --git a/OpenGL/platform/egl.py b/OpenGL/platform/egl.py
index e74f3dd8..0edfbbf6 100644
--- a/OpenGL/platform/egl.py
+++ b/OpenGL/platform/egl.py
@@ -64,6 +64,12 @@ class EGLPlatform( baseplatform.BasePlatform ):
             return None
     @baseplatform.lazy_property
     def OpenGL(self): return self.GL
+    @baseplatform.lazy_property
+    def GLX(self):
+        try:
+            return ctypesloader.loadLibrary(ctypes.cdll, "GLX", mode=ctypes.RTLD_GLOBAL)
+        except OSError as err:
+            return self.GL

     @baseplatform.lazy_property
     def EGL(self):
@@ -103,4 +109,6 @@ class EGLPlatform( baseplatform.BasePlatform ):
     DEFAULT_FUNCTION_TYPE = staticmethod( ctypes.CFUNCTYPE )
     @baseplatform.lazy_property
     def GetCurrentContext( self ):
-        return self.EGL.eglGetCurrentContext
+        def either(*args):
+            return self.EGL.eglGetCurrentContext(*args) or self.GLX.glXGetCurrentContext(*args)
+        return either
diff --git a/OpenGL/platform/glx.py b/OpenGL/platform/glx.py
index c67e9cf6..33b515be 100644
--- a/OpenGL/platform/glx.py
+++ b/OpenGL/platform/glx.py
@@ -40,7 +40,6 @@ class GLXPlatform(baseplatform.BasePlatform):
         except OSError:
             return None

-    # GLX doesn't seem to have its own loadable module?
     @baseplatform.lazy_property
     def GLX(self):
         try:
t20100 commented 1 year ago

The same issue is there with PyQt|PySide depending on the Qt Platform Abstraction in use.

No matter of the default detection mechanism, wouldn't it make sense/be possible to have an way to set the platform programmatically?

For instance, with PyQt|PySide, it is possible to retrieve the platform at runtime with QGuiApplication.platformName, and that could be used to set it in pyopengl.

mcfletch commented 1 year ago

Sure, having it be a thing you can set via code is fine. But it has to be set basically at import-time to avoid funky issues, so you wind up with a thin wrapper around setting the PYOPENGL_PLATFORM environment variable before import. Just added a function OpenGl.setPlatform('glx') which is just that, but it's meh IMO.

What I was looking for was a way to properly select the platform automatically. The primary concern being that I don't want to load e.g. a whole X-windows client library just to see if the process is running an X window, same issue with Qt/Gtk/etc. Way too heavy-weight to use for 'guess which approach to use'. Secondary concern is that the software doesn't have to start the X/Wayland connection immediately; and in theory at any moment it could make a choice to do X vs. Wayland... so until we see an actual rendering context there really isn't a right guess as to which type of context it is AFAICS.