pyopengl
pyopengl copied to clipboard
unhashable type exception when using glVertexAttribPointer with OSMesa and OpenGL 2.1
I'm getting this exception whenever i call glVertexAttribPointer in an OpenGL 2.1 context with OSMesa. That didn't happen when I was using an OpenGL 4.3 context with GLFW
I'm using openSUSE Tumbleweed with Mesa graphics drivers (19.1.5 version)
This is the full exception message:
Traceback (most recent call last):
File "main.py", line 165, in <module>
main()
File "main.py", line 152, in main
shape.render()
File "main.py", line 118, in render
self.teapot.render(self.material.shader)
File "main.py", line 66, in render
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0))
File "/home/guilherme/.local/lib/python3.7/site-packages/OpenGL/latebind.py", line 61, in __call__
return self.wrapperFunction( self.baseFunction, *args, **named )
File "/home/guilherme/.local/lib/python3.7/site-packages/OpenGL/GL/VERSION/GL_2_0.py", line 426, in glVertexAttribPointer
contextdata.setValue( key, array )
File "/home/guilherme/.local/lib/python3.7/site-packages/OpenGL/contextdata.py", line 65, in setValue
current = storage.get( context )
TypeError: unhashable type
I'm trying to render something in headless mode, that's why I'm using OSMesa and gl2.1. Any help I can get here please?
The basic problem here is that somehow your current context is a non-hashable type, I just don't see how it does.
On OSMesa the contextdata module should be using an OpaquePointer instance which explicitly should have a hash method. Do you have a test case I can use to debug, as my attempt at a recreation is running correctly.
Thanks for your attention, but unfortunately I don't have my test case right now. as we stopped trying to run PyOpenGL in headless mode a few months ago.
But if it's going to help you in the development, I can send you the point where I left off after I go back to work tomorrow (my holidays end today). I think I still have this issue there.
Again thanks for your work, though I'm still curious why I can only use older OpenGL versions with OSMesa. Is it a OSMesa limitation, or the newer GL support for PyOpenGL is still WIP? If it is, there is a chance I'll be able to help with that a little.
OSMesa should expose the underlying OpenGL implementation. On my current mesa/osmesa OpenGL release shows OpenGL 3.1 on an Ubuntu 18.04 machine (i.e. the built-in Mesa software renderer supports OpenGL 3.1). An EGL off-screen context on the VMWare driver shows 3.1, consistent with the driver being provided by mesa.
On an EGL/nVidia off-screen context (on the same machine) OpenGL shows release 4.6. Which is what you would expect from an nVidia binary driver (and what you see if you create an on-screen window instead of an off-screen context).
PyOpenGL support should be current with defined extensions (well, within a month or so at this point), but it is entirely possible to find extensions where the auto-wrapping has resulted in a broken wrapper. That said, this looks like a "the opengl library you're using doesn't support the opengl version you'd like" issue.
Dears @mcfletch ,This is a test case,which comes the error "{TypeError}unhashable type" at the code line "gl.glVertexPointer(2, gl.GL_FLOAT, 0, V_ori_gl_2d_ptr)", and my OSMesa version: 4.5 (Compatibility Profile) Mesa 23.2.1-1ubuntu3.1~22.04.2
import numpy as np
import os
if not os.environ.get('PYOPENGL_PLATFORM'):
os.environ['PYOPENGL_PLATFORM'] = 'osmesa'
import ctypes
from OpenGL.osmesa import *
from OpenGL import arrays
import OpenGL.GL as gl
class BodyAwareReshaper:
def __init__(self, reg_coeff_canvas):
self.reg_coeff_canvas = reg_coeff_canvas
def draw_body_part_mask(self, mesh_vertices, mesh_faces, projection_mat):
ver_num = len(mesh_vertices)
V_home = np.ones((ver_num, 4), dtype=np.float32)
V_home[:, :3] = mesh_vertices
projection_mat = np.transpose(projection_mat[:3, :])
V_proj_3d = np.matmul(V_home, projection_mat)
V_proj = V_proj_3d[:, :2]
V_proj[:, 0] = V_proj[:, 0] / V_proj_3d[:, 2]
V_proj[:, 1] = V_proj[:, 1] / V_proj_3d[:, 2]
oneVec = np.ones(2, dtype=np.float32)
V_ori_gl_2d = 2 * V_proj * self.reg_coeff_canvas - oneVec
# Ensure data type and flatten array
V_ori_gl_2d = V_ori_gl_2d.flatten().astype(np.float32)
print(f"V_ori_gl_2d: {V_ori_gl_2d}")
# OpenGL settings
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
gl.glMatrixMode(gl.GL_MODELVIEW)
gl.glLoadIdentity()
# Start OpenGL drawing
gl.glPushMatrix()
gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
try:
# Convert numpy array to a C-contiguous array
V_ori_gl_2d_ptr = V_ori_gl_2d.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
print(f"Pointer Type: {type(V_ori_gl_2d_ptr)}")
# Setting vertex pointer and draw
gl.glVertexPointer(2, gl.GL_FLOAT, 0, V_ori_gl_2d_ptr)
gl.glDrawArrays(gl.GL_POINTS, 0, len(V_ori_gl_2d) // 2)
except Exception as e:
print(f"Error during OpenGL call: {e}")
finally:
gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
gl.glPopMatrix()
# Flush to ensure drawing commands are executed
gl.glFlush()
def display_callback():
mesh_vertices = np.random.rand(10, 3).astype(np.float32)
mesh_faces = np.array([0, 1, 2])
projection_mat = np.eye(4, dtype=np.float32)
# Initialize and draw
reshaper = BodyAwareReshaper(reg_coeff_canvas=np.float32([1.0 / canvas_width, 1.0 / canvas_height]))
reshaper.draw_body_part_mask(mesh_vertices, mesh_faces, projection_mat)
ctx = OSMesaCreateContext(OSMESA_RGBA, None)
canvas_width = 832
canvas_height = 1216
bufRGBA = arrays.GLubyteArray.zeros((canvas_height, canvas_width, 4))
if not OSMesaMakeCurrent(ctx, bufRGBA, gl.GL_UNSIGNED_BYTE, canvas_width, canvas_height):
raise RuntimeError("OSMesaMakeCurrent failed!")
gl.glViewport(0, 0, canvas_width, canvas_height)
gl.glEnable(gl.GL_DEPTH_TEST)
display_callback()