glfw / glfw

A multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input
https://www.glfw.org
zlib License
13.02k stars 5.24k forks source link

GLFW (Python) in WSL2 #2284

Open danchitnis opened 1 year ago

danchitnis commented 1 year ago

Hello, I am trying to write a very simple test code using pyGLFW:

import glfw
from OpenGL import GL as gl
import numpy as np

def checkGLError():
    err = gl.glGetError()
    while err != gl.GL_NO_ERROR:
        print(err)
        err = gl.glGetError()

vertex_shader_text = """
#version 330
attribute vec2 a_position;
void main()
{
    gl_Position = vec4(a_position, 0.0, 1.0);
}
"""

fragment_shader_text = """
#version 330
precision mediump float;  
void main()
{
    gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
"""

vertices = np.array([-0.8, -0.8, 
                        0.8, -0.8, 
                        0.0,  0.8], dtype=np.float32)

vertex_buffer = np.empty(1, dtype=np.uint32)

# Initialize the library
if not glfw.init():
    exit()
# Create a windowed mode window and its OpenGL context
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)

window = glfw.create_window(640, 480, "Hello World", None, None)
if not window:
    glfw.terminate()
    exit()
# Make the window's context current
glfw.make_context_current(window)
glfw.swap_interval(1)

print(glfw.get_version_string())
print(gl.glGetString(gl.GL_VERSION))

vertex_shader = gl.glCreateShader(gl.GL_VERTEX_SHADER)
gl.glShaderSource(vertex_shader, vertex_shader_text)
gl.glCompileShader(vertex_shader)

success = gl.glGetShaderiv(vertex_shader, gl.GL_COMPILE_STATUS)
if not success:
    print("Shader compilation failed")
    print(gl.glGetShaderInfoLog(vertex_shader))

fragment_shader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
gl.glShaderSource(fragment_shader, fragment_shader_text)
gl.glCompileShader(fragment_shader)

success = gl.glGetShaderiv(fragment_shader, gl.GL_COMPILE_STATUS)
if not success:
    print("Shader compilation failed")
    print(gl.glGetShaderInfoLog(fragment_shader))

program = gl.glCreateProgram()
gl.glAttachShader(program, vertex_shader)
gl.glAttachShader(program, fragment_shader)
gl.glLinkProgram(program)

vbo = gl.glGenBuffers(1)

gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo)
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertices.nbytes, vertices, gl.GL_STATIC_DRAW)

positionLocation = gl.glGetAttribLocation(program, "a_position")
gl.glVertexAttribPointer(positionLocation, 2, gl.GL_FLOAT, gl.GL_FALSE, 0, None)
gl.glEnableVertexAttribArray(positionLocation)

gl.glUseProgram(program)

gl.glClearColor(0.0, 0.5, 0.0, 1.0)

# Loop until the user closes the window
while not glfw.window_should_close(window):
    # Render here, e.g. using pyOpenGL
    gl.glClear(gl.GL_COLOR_BUFFER_BIT)

    gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3)

    # Swap front and back buffers
    glfw.swap_buffers(window)

    # Poll for and process events
    glfw.poll_events()

glfw.terminate()
print("Done!")

However, the code fails in WSL2 on the line: gl.glVertexAttribPointer(positionLocation, 2, gl.GL_FLOAT, gl.GL_FALSE, 0, None) with the error:

aceback (most recent call last):
  File "/home/danial/code/pyglplot/temp/testg1.py", line 87, in <module>
    gl.glVertexAttribPointer(positionLocation, 2, gl.GL_FLOAT, gl.GL_FALSE, 0, None)
  File "/home/danial/.local/lib/python3.10/site-packages/OpenGL/latebind.py", line 63, in __call__
    return self.wrapperFunction( self.baseFunction, *args, **named )
  File "/home/danial/.local/lib/python3.10/site-packages/OpenGL/GL/VERSION/GL_2_0.py", line 469, in glVertexAttribPointer
    contextdata.setValue( key, array )
  File "/home/danial/.local/lib/python3.10/site-packages/OpenGL/contextdata.py", line 58, in setValue
    context = getContext( context )
  File "/home/danial/.local/lib/python3.10/site-packages/OpenGL/contextdata.py", line 40, in getContext
    raise error.Error(
OpenGL.error.Error: Attempt to retrieve context when no valid context

Otherwise, the window creation works fine. The code also runs fine in Windows natively.

I have run similar codes with other libraries which use GLFW like pyglet and VisPy, and both work fine, so I suspect there is some setting related to GLFW which is causing the issue. Any suggestions on how to debug further?

The output of glxinfo -B is:

display: :0  screen: 0
direct rendering: Yes
Extended renderer info (GLX_MESA_query_renderer):
    Vendor: Microsoft Corporation (0xffffffff)
    Device: D3D12 (Intel(R) UHD Graphics 630) (0xffffffff)
    Version: 22.2.5
    Accelerated: yes
    Video memory: 16435MB
    Unified memory: yes
    Preferred profile: core (0x1)
    Max core profile version: 4.1
    Max compat profile version: 4.1
    Max GLES1 profile version: 1.1
    Max GLES[23] profile version: 3.0
OpenGL vendor string: Microsoft Corporation
OpenGL renderer string: D3D12 (Intel(R) UHD Graphics 630)
OpenGL core profile version string: 4.1 (Core Profile) Mesa 22.2.5
OpenGL core profile shading language version string: 4.10
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile

OpenGL version string: 4.1 (Compatibility Profile) Mesa 22.2.5
OpenGL shading language version string: 4.10
OpenGL context flags: (none)
OpenGL profile mask: compatibility profile

OpenGL ES profile version string: OpenGL ES 3.0 Mesa 22.2.5
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.00

Also glxgears and glxheads work fine.

elmindreda commented 1 year ago

Hmm, is GLFW using Wayland or X11? One defaults to EGL and the other to GLX. If GLFW and the OpenGL bindings are talking to different context creation APIs then that could explain it.

danchitnis commented 1 year ago

I am getting this:

b'3.3.8 X11 GLX EGL OSMesa clock_gettime evdev shared'
b'4.1 (Core Profile) Mesa 22.2.5'

on these commands:

print(glfw.get_version_string())
print(gl.glGetString(gl.GL_VERSION))

I know that WSLg runs on Wayland, so how to force GLFW (and OpenGL) to use Wayland?

elmindreda commented 1 year ago

WSLg supports both X11 and Wayland, though it isn't clear to me from the above which APIs the Python binding is using.

If you want to switch self-compiled GLFW 3.3 to using Wayland then you need to compile it for Wayland. If you are using the GLFW package from your distribution, install the Wayland variant of it if there is one.

danchitnis commented 1 year ago

Thanks for your advice. I think there is an issue with OpenGL and window context creation. I did some tests and only got it working in the following condition:

glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 1)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 5)

glfw.window_hint(glfw.CONTEXT_CREATION_API, glfw.EGL_CONTEXT_API)

If I choose a different context version or native context, it doesn't work. This is with the X11 backend. Although I am enforcing version 1.5, I am still getting version 4.1 when doing GL_VERSION, and in fact, shaders compile with #version 330. So I am not sure what the connection between the two is.

In Wayland, it works with both native context and EGL as long as it is explicitly enforced. However, the windows have a cursor issue, and I get this error:

GLFWError: (65544) b'Wayland: Focusing a window requires user interaction'

The same OpenGL version problem occurs in Wayland similar to X11 in both native and EGl contexts.

In fact, is the glfw.window_hint setting the OpenGL version or EGL? in this case it looks like it is setting the EGL version rather OpenGL.

elmindreda commented 1 year ago

Although I am enforcing version 1.5, I am still getting version 4.1 when doing GL_VERSION, and in fact, shaders compile with #version 330. So I am not sure what the connection between the two is.

The GLFW_CONTEXT_VERSION_MAJOR and GLFW_CONTEXT_VERSION_MINOR hints specify the minimum version you require, but the system is free to give you a context of any later version that's compatible with what you asked for. In this case you got OpenGL 4.1 with the compatibility profile, which can do everything OpenGL 1.5 can do.

In Wayland, it works with both native context and EGL as long as it is explicitly enforced.

This is likely because EGL is the native context creation API on Wayland.

However, the windows have a cursor issue, and I get this error:

GLFWError: (65544) b'Wayland: Focusing a window requires user interaction'

How odd, you shouldn't get that error with GLFW 3.3.8 unless you're calling glfwShowWindow or glfwFocusWindow.

What cursor issue did you get?

danchitnis commented 1 year ago
GLFWError: (65544) b'Wayland: Focusing a window requires user interaction'

The above was with standard Ubuntu libglfw 3.3.6-1 package. Now when I use the 3.3.8 shipped with pyGLFW I get the following error:

GLFWError: (65544) b'Wayland: Standard cursor shape unavailable'

The error is that the window opens with the correct OpenGL drawing, however, the title bar is blank gray and there is no closing button on the title bar. I have to do Crtl+C to close the window.

elmindreda commented 1 year ago

The above was with standard Ubuntu libglfw 3.3.6-1 package.

Oh, that makes sense. That was an issue in 3.3.6 but not in the latest release.

Now when I use the 3.3.8 shipped with pyGLFW I get the following error:

GLFWError: (65544) b'Wayland: Standard cursor shape unavailable'

This could be the active cursor theme lacking that particular cursor, or it could be a bug in the GLFW Wayland code.

The error is that the window opens with the correct OpenGL drawing, however, the title bar is blank gray and there is no closing button on the title bar. I have to do Crtl+C to close the window.

Those are the GLFW fallback decorations for Wayland and yes, they're very limited. Better decorations are on the way!

elmindreda commented 8 months ago

Now when I use the 3.3.8 shipped with pyGLFW I get the following error:

GLFWError: (65544) b'Wayland: Standard cursor shape unavailable'

This has been fixed in GLFW 3.3.9 with 1d766c8b39936469280001a18f506c4efb394cb8.

The error is that the window opens with the correct OpenGL drawing, however, the title bar is blank gray and there is no closing button on the title bar. I have to do Crtl+C to close the window.

This has been fixed in GLFW 3.3.9 by adding support for libdecor. If you install the libdecor-0-0 package, GLFW will now detect this and provide better window decorations.

ucacaxm commented 4 months ago

Any update ? I have the same problem. Thanks