FlorianRhiem / pyGLFW

Python bindings for GLFW
MIT License
233 stars 36 forks source link

GLFWError: (65542) b'WGL: The driver does not appear to support OpenGL' #79

Closed markusgritsch closed 6 months ago

markusgritsch commented 6 months ago

Hi Florian,

I installed PyGLFW on my Windows 10 (version 22H2) laptop which has integrated Intel HD Graphics 3000. When I run the example at the bottom of the page https://github.com/FlorianRhiem/pyGLFW I get the following traceback:

C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\glfw\__init__.py:914: GLFWError: (65542) b'WGL: The driver does not appear to support OpenGL'
  warnings.warn(message, GLFWError)

Initially I came across this error when trying to run the examples from https://github.com/pthom/imgui_bundle.

The thing is, I can use GLFW when compiling the Nim bindings for Dear ImGui without problems. Also the precompiled Dear ImGui examples from https://www.dearimgui.com/binaries/imgui-demo-binaries-20240105.zip are running fine.

It would be super nice if you could spend a bit of your time reading the Issue I files here https://github.com/pthom/imgui_bundle/issues/206 and maybe give some advice.

Thanks in advance!

FlorianRhiem commented 6 months ago

Hey Markus,

as Pascal Thomet notes in that issue, pyGLFW is just a wrapper around the C library GLFW. The error you receive comes from GLFW itself, so either pyGLFW makes (or omits) any wrong calls to cause this error, or the library it calls hasn't been compiled correctly to work on your system, or the library itself doesn't work on your system.

If the rather simple example causes that issue, you could first try running it with the pre-compiled library downloaded from glfw.org instead of the one included in the wheel, using the PYGLFW_LIBRARY environment variable set to the path of that library. If that also doesn't work, please try the almost identical example from GLFW in C and see if that works. The next step would be to compile GLFW on your system, but that might be a bit more work.

My suspicion is that if the Python example won't work with whatever GLFW library you're using, the C version won't work either, as I suspect the issue to lie outside this wrapper, but this way we should find out for certain.

markusgritsch commented 6 months ago

Hi Florian,

thank you for the quick answer!

When replacing C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\glfw\glfw3.dll with the precompiled .dll from glfw.org, the same error is shown.

Then I downloaded https://github.com/glfw/glfw/releases/download/3.4/glfw-3.4.zip and https://cmake.org/download/, configured it for mingw (which I have from my Nim installation), and ran mingw32-make. Surprisingly compilation went flawlessly, and also all the automatically compiled examples are running fine. grafik

I repeated the build process, this time having checked BUILD_SHARED_LIBS. Again, everything worked, and the examples now need the compiled glfw3.dll being located in the same directory as the example executables. grafik

Finally, replacing C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\glfw\glfw3.dll with my compiled glfw3.dll again gives the same error:

C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\glfw\__init__.py:914: GLFWError: (65542) b'WGL: The driver does not appear to support OpenGL'
  warnings.warn(message, GLFWError)

So to me it seems the most likely explanation is your suggested so either pyGLFW makes (or omits) any wrong calls to cause this error. What do you think? And what should I check next?

Thanks for your help!

FlorianRhiem commented 6 months ago

That's unexpected. Just to be sure, have you ran the example from the documentation I linked instead of any other examples? Also, is the warning raised when you call glfw.create_window(640, 480, "Hello World", None, None) or at some other point of the code? You can set glfw.ERROR_REPORTING to True or raise to get a full traceback. And have you used PYGLFW_LIBRARY to make sure your version of gflw3.dll is the one that is being used? You can also print glfw._glfw to see the used library. If all that happens is glfw.init being called without arguments and then glfw.create_window being called, there's not much that could cause this error.

markusgritsch commented 6 months ago

That's unexpected. Just to be sure, have you ran the example from the documentation I linked instead of any other examples?

Yes, I replaced the content of one demo with the code from your link and recompiled. I had to comment the line containing the call glClear(GL_COLOR_BUFFER_BIT); because of unresolved symbols, but after that it ran fine and a black window was shown.

Also, is the warning raised when you call glfw.create_window(640, 480, "Hello World", None, None) or at some other point of the code? You can set glfw.ERROR_REPORTING to True or raise to get a full traceback.

Yes, _glfw.glfwCreateWindow(...) raises the error:

Traceback (most recent call last):
  File "C:\Users\mgr\Downloads\imgui-demo-binaries-20240105\pyGLFW Test.py", line 36, in <module>
    main()
  File "C:\Users\mgr\Downloads\imgui-demo-binaries-20240105\pyGLFW Test.py", line 15, in main
    window = glfw.create_window(640, 480, "Hello World", None, None)
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\glfw\__init__.py", line 1266, in create_window
    return _glfw.glfwCreateWindow(width, height, _to_char_p(title),
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\glfw\__init__.py", line 689, in errcheck
    _reraise(exc[1], exc[2])
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\glfw\__init__.py", line 70, in _reraise
    raise exception.with_traceback(traceback)
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\glfw\__init__.py", line 668, in callback_wrapper
    return func(*args, **kwargs)
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\glfw\__init__.py", line 912, in _handle_glfw_errors
    raise GLFWError(message, error_code=error_code)
glfw.GLFWError: (65542) b'WGL: The driver does not appear to support OpenGL'

And have you used PYGLFW_LIBRARY to make sure your version of gflw3.dll is the one that is being used?

Yes, first I replaced the original .dll in C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\glfw\, then I set PYGLFW_LIBRARY to C:\\Users\\mgr\\Downloads\\glfw-3.4\\bin\\src\\glfw3.dll with the same error message.

You can also print glfw._glfw to see the used library.

<CDLL 'C:\Users\mgr\Downloads\glfw-3.4\bin\src\glfw3.dll', handle 7ff9de540000 at 0x21aa8404be0>

If all that happens is glfw.init being called without arguments and then glfw.create_window being called, there's not much that could cause this error.

Yes, it's getting a bit frustrating. On a similar setup on my PC at work everything is running fine.

FlorianRhiem commented 6 months ago

The following is a minimal example of using ctypes to call glfwInit and glfwCreateWindow, with all struct wrappers, fancy library loading, etc removed. If this works, there's some issue in pyGLFW. If it doesn't, then something prevents GLFW wrapped with Python from working on your system, though I couldn't say what. Perhaps some incompatibility between whatever VC runtime your CPython was built for vs. that GLFW was built for, or something like that.

import os
import ctypes

_glfw = ctypes.CDLL(os.environ['PYGLFW_LIBRARY'])

_glfw.glfwInit.restype = ctypes.c_int
_glfw.glfwInit.argtypes = []
print(_glfw.glfwInit())

_glfw.glfwCreateWindow.restype = ctypes.c_void_p
_glfw.glfwCreateWindow.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_void_p]
print(_glfw.glfwCreateWindow(640, 480, "Hello World".encode('utf-8'), ctypes.c_void_p(0), ctypes.c_void_p(0)))
markusgritsch commented 6 months ago

Thanks Florian, for going such lenght with my Problem! It seems to work, and outputs

1
None

I assume, None indicates, that there is a problem with my Python setup, right?

The strange thing is, I have a supposedly identical installation of this Python version at work, and there are no problems. I try to reinstall things here.

FlorianRhiem commented 6 months ago

There should be a pointer to a window, None indicates that glfwCreateWindow failed to create one. I'm sorry that I can't really help you there, as I have no idea what might be causing this. You could try using a different Python, e.g. by installing the current Python 3.12.3 and seeing if that helps in any way. Updating your graphics driver and things like that would normally be reasonable steps for an error like this, but with GLFW working fine when used from C, that shouldn't be necessary.

markusgritsch commented 6 months ago

Installed python-3.12.3-amd64.exe -- same Problem.

FlorianRhiem commented 6 months ago

Out of curiosity, and to see if there is anything wrong with GLFW in particular, does the following example using GLUT work?

from OpenGL.GLUT import *
from OpenGL.GL import *

def display():
    glClear(GL_COLOR_BUFFER_BIT)
    glutSwapBuffers()

glutInit()
glutCreateWindow('window')
glutDisplayFunc(display)
glutMainLoop()
markusgritsch commented 6 months ago

Running the example gives me

Traceback (most recent call last):
  File "C:\Users\mgr\Downloads\imgui-demo-binaries-20240105\pyGLUT.py", line 8, in <module>
    glutInit()
  File "C:\Users\mgr\AppData\Local\Programs\Python\Python312\Lib\site-packages\OpenGL\GLUT\special.py", line 333, in glutInit
    _base_glutInit( ctypes.byref(count), holder )
  File "C:\Users\mgr\AppData\Local\Programs\Python\Python312\Lib\site-packages\OpenGL\platform\baseplatform.py", line 423, in __call__
    raise error.NullFunctionError(
OpenGL.error.NullFunctionError: Attempt to call an undefined function glutInit, check for bool(glutInit) before calling

also on the otherwise "good" machine at work. Googling the error message suggested downloading glut.dll or freeglut.dll and rename it to glut64.dll or something, but everything quite vague.

FlorianRhiem commented 6 months ago

Ah, okay. Yes, that library is needed, I was under the impression that it was included in the PyOpenGL package, but it seems that's not the case.

You might have some luck with the GLFW community itself, with the minimal example using ctypes instead of this wrapper, though I'm not sure there either. I don't think I can help you with this issue.

markusgritsch commented 6 months ago

Thanks Florian, you have already invested way more time into my problem than anyone could reasonably expect.

I installed pyglet and this simple program

import pyglet
window = pyglet.window.Window()

gives this traceback

Traceback (most recent call last):
  File "C:\Users\mgr\Downloads\examples\opengl\opengl_scissor.py", line 14, in <module>
    window = pyglet.window.Window(width=500, height=500)
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\pyglet\window\win32\__init__.py", line 104, in __init__
    super(Win32Window, self).__init__(*args, **kwargs)
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\pyglet\window\__init__.py", line 583, in __init__
    self._create_projection()
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\pyglet\window\__init__.py", line 591, in _create_projection
    shader.Shader(self._default_vertex_source, 'vertex'),
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\pyglet\graphics\shader.py", line 795, in __init__
    shader_id = glCreateShader(shader_type)
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\pyglet\gl\lib_wgl.py", line 66, in __call__
    return self.func(*args, **kwargs)
  File "C:\Users\mgr\AppData\Roaming\Python\Python310\site-packages\pyglet\gl\lib.py", line 25, in MissingFunction
    raise MissingFunctionException(name, requires, suggestions)
pyglet.gl.lib.MissingFunctionException: glCreateShader is not exported by the available OpenGL driver.  OpenGL 2.0 is required for this functionality.

It says OpenGL 2.0 is required, which my driver definitely supports.

GLview tells me the driver supports 3.1, grafik which matches my findings from the Nim ImGUI examples here: https://github.com/pthom/imgui_bundle/issues/206

Somehow the OpenGL version found when I did the C compilation seems to be different from the one Python finds. Do you have any Idea how I can locate the OpenGL (.dll?) which is used by e.g. pyglet?

FlorianRhiem commented 6 months ago

Perhaps you could view the loaded DLLs using Microsoft Process Viewer.

markusgritsch commented 6 months ago

Good news, its working now :)

This snippet

from pyglet.gl import *
from ctypes import *

print(cast(glGetString(GL_VENDOR), c_char_p).value)
print(cast(glGetString(GL_RENDERER), c_char_p).value)
print(cast(glGetString(GL_VERSION), c_char_p).value)

gave on my Laptop

b'Microsoft Corporation'
b'GDI Generic'
b'1.1.0'

So when called from Python, the Intel graphics driver does not work and Windows uses this fallback driver.

Googling let me to this issue https://github.com/pyglet/pyglet/issues/374 where the same problem is described. There are several links in the comments, how to fix the issue (https://github.com/pal1000/save-legacy-intel-graphics?tab=readme-ov-file, https://gist.github.com/rb-dahlb/26f316c5b6089807a139fc44ee69f0d1) and also some community-patched driver installer: https://winraid.level1techs.com/t/get-your-intel-hd3000-sandy-bridge-windows-10-64bit-drivers-here/40044 This comment on that page also contains a good explanation, what causes the problem, and how to fix it: https://winraid.level1techs.com/t/get-your-intel-hd3000-sandy-bridge-windows-10-64bit-drivers-here/40044/22

After installing this patched driver, the above snippet now outputs

b'Intel'
b'Intel(R) HD Graphics 3000'
b'3.1.0 - Build 9.17.10.4459'

All is well.