mcfletch / pyopengl

Repository for the PyOpenGL Project
Other
312 stars 95 forks source link

unhashable type exception when using glVertexAttribPointer with OSMesa and OpenGL 2.1 #33

Open sabtorres opened 4 years ago

sabtorres commented 4 years ago

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?

mcfletch commented 4 years ago

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.

sabtorres commented 4 years ago

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.

mcfletch commented 4 years ago

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.

tengshaofeng commented 1 month ago

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()