pythonpangolin

Code crashes when put into separate functions within a class


I've ran into an odd situation in Python where code works if I put everything in the __init__ function of a class, but if I break it up into functions within the class, the otherwise identical code crashes. Here is my current example:

This works:

# SimpleDisplay5.py

import faulthandler
import pypangolin as pango
import OpenGL.GL as gl
import numpy as np
import time

class Display3D(object):

    def __init__(self):
        self.win = pango.CreateWindowAndBind('Pangolin Viewer', 640, 480)
        gl.glEnable(gl.GL_DEPTH_TEST)

        pm = pango.ProjectionMatrix(640, 480, 420, 420, 320, 240, 0.1, 1000)
        mv = pango.ModelViewLookAt(-0, 0.5, -3, 0, 0, 0, pango.AxisY)
        self.s_cam = pango.OpenGlRenderState(pm, mv)

        ui_width = 180

        handler = pango.Handler3D(self.s_cam)
        self.d_cam = (
            pango.CreateDisplay()
            .SetBounds(
                pango.Attach(0),
                pango.Attach(1),
                pango.Attach.Pix(ui_width),
                pango.Attach(1),
                -640.0 / 480.0,
            )
            .SetHandler(handler)
        )

        self.points = np.random.uniform(-1.0, 1.0, (100, 3)).astype(np.float32)

        gl.glPointSize(5)
        gl.glColor3f(1.0, 0.0, 0.0)  # red
        
        while not pango.ShouldQuit():
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

            self.d_cam.Activate(self.s_cam)

            pango.glDrawPoints(self.points)

            pango.FinishFrame()
        # end while
    # end function

# end class

def main():
    faulthandler.enable()

    np.set_printoptions(suppress=True)

    disp3d = Display3D()

    while True:
        time.sleep(0.5)
    # end while

# end function

if __name__ == "__main__":
    main()

This crashes with a segmentation fault:

# SimpleDisplay6.py

import faulthandler
import pypangolin as pango
import OpenGL.GL as gl
import numpy as np
import time

class Display3D(object):

    def __init__(self):
        self.viewerInit()

        self.viewerRefresh()
    # end function

    def viewerInit(self):
        self.win = pango.CreateWindowAndBind('Pangolin Viewer', 640, 480)
        gl.glEnable(gl.GL_DEPTH_TEST)

        pm = pango.ProjectionMatrix(640, 480, 420, 420, 320, 240, 0.1, 1000)
        mv = pango.ModelViewLookAt(-0, 0.5, -3, 0, 0, 0, pango.AxisY)
        self.s_cam = pango.OpenGlRenderState(pm, mv)

        ui_width = 180

        handler = pango.Handler3D(self.s_cam)
        self.d_cam = (
            pango.CreateDisplay()
            .SetBounds(
                pango.Attach(0),
                pango.Attach(1),
                pango.Attach.Pix(ui_width),
                pango.Attach(1),
                -640.0 / 480.0,
            )
            .SetHandler(handler)
        )

        self.points = np.random.uniform(-1.0, 1.0, (100, 3)).astype(np.float32)

        gl.glPointSize(5)
        gl.glColor3f(1.0, 0.0, 0.0)  # red
    # end function

    def viewerRefresh(self):
        while not pango.ShouldQuit():
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

            self.d_cam.Activate(self.s_cam)

            pango.glDrawPoints(self.points)

            pango.FinishFrame()
        # end while
    # end function
# end class

def main():
    faulthandler.enable()

    np.set_printoptions(suppress=True)

    disp3d = Display3D()

    while True:
        time.sleep(0.5)
    # end while

# end function

if __name__ == "__main__":
    main()

Specifically, the 2nd program crashes when I mouse over the Pangolin viewer window. Here is the terminal output for the 2nd program:

$ python3 SimpleDisplay6.py 
Fatal Python error: Segmentation fault

Current thread 0x00007f4384b05740 (most recent call first):
  File "SimpleDisplay6.py", line 54 in viewerRefresh
  File "SimpleDisplay6.py", line 14 in __init__
  File "SimpleDisplay6.py", line 64 in main
  File "SimpleDisplay6.py", line 73 in <module>
Segmentation fault (core dumped)

Line 54 in the 2nd program is:

        pango.FinishFrame()

Note that the only difference between the 2 programs is in the 2nd, I divided up the __init__ content into 2 separate functions. Can somebody explain what is going on here or how this is even possible? Thinking of how this would break down into CPython, I would have figured it should have been identical.

I did post a question in the Pangolin viewer repo https://github.com/stevenlovegrove/Pangolin/issues/861, but the more I consider the situation I'm not sure this is a Pangolin concern since the 1st example works.

Moreover, I recall something very similar happening before when I attempted to call OpenCV functions from within a Qt frame (I don't have the code for that currently however).

I should probably also mention I'm aware the while True in main() is never reached in either program, I left that code in since my eventual plan was to start the Pangolin viewer on a separate thread when I get this current problem worked out.

Any suggestions as to the cause of this or what I should check next?


Solution

  • With the loud disclaimer that I know nothing about this Python extension, the circumstantial evidence is that one or more of the pango.ProjectionMatrix, pango.ModelViewLookAt, and pango.Handler3D objects must still be alive during the calls to pango.glDrawPoints and/or pango.FinishFrame. This is arguably a bug in pango; the usual expectation is that it keeps the Python objects (or their coordinate C++ objects) alive so long as any relevant Python object is alive.