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?
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.