Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pyglet's Window Display For Apple Silicon (M1, M2) Devices #1100

Open
abanuelo opened this issue May 2, 2024 · 5 comments
Open

Pyglet's Window Display For Apple Silicon (M1, M2) Devices #1100

abanuelo opened this issue May 2, 2024 · 5 comments

Comments

@abanuelo
Copy link

abanuelo commented May 2, 2024

Background

I had a question regarding a strange Apple Silicon specific behavior I am facing when working with pyglet. I have noticed that if we use pyglet < 1.5.28 as a dependency for trimesh on Apple Silicon devices, after it runs a show() from trimesh which uses a class named SceneViewer that has pyglet <2.0 dependencies to show the screen, when you close out the popped up display window, it completely terminates the program. You can see it best represented in this video in our issues: BerkeleyLearnVerify/Scenic#230

Some more information describing the behavior can be found on this issue from the trimesh side: mikedh/trimesh#2131

However when I downgrade the pyglet dependency to say 1.5.26 for trimesh, I am able to close out the opened display window and still have the program continue without crashing. This can be best illustrated by this video here: BerkeleyLearnVerify/Scenic#248

Question?

Were there any implementation differences between pyglet 1.5.26 and 1.5.28 that aren't reflected in the changelog regarding how to handle terminating a opened display window?

@benmoran56
Copy link
Member

The were quite a few bugfixes that were backported, and I believe some changes to the text and font modules. There were also some fixes related to memory leaks and references.

It might be necessary to do a git bisect to trace down the exact changes.

The default behavior of the pyglet event loop is to exit when all Windows are closes. The can be overridden of course: https://github.com/pyglet/pyglet/blob/master/pyglet/app/base.py#L277

@abanuelo
Copy link
Author

abanuelo commented May 6, 2024

As a follow up just so we can get some alignment @benmoran56 , what I mean by saying "my program terminates", is that all subsequent code after the window is closed never gets executed because the process running the python snippet terminates. To make a more reproducible example for you to replicate try: running this snippet of code with pyglet version 1.5.28. Once you close out the window, the print("Will never reach this!!!!!") never shows and the while True: is never re-executed.

import pyglet

window = pyglet.window.Window(width=800, height=600)

label = pyglet.text.Label('Hello, Pyglet!',
                          font_name='Arial',
                          font_size=36,
                          x=window.width // 2, y=window.height // 2,
                          anchor_x='center', anchor_y='center')

@window.event
def on_draw():
    window.clear()
    label.draw()

while True:
    pyglet.app.run()
    print("Will never reach this!!!!!")

Video:

pyglet-1.5.28-error.mov

@caffeinepills
Copy link
Collaborator

I'm not sure we really support looping a pyglet.app.run() call, but I think I understand your issue.

I think when the loop terminates it will terminate the whole program for the alternate loop.

pyglet/pyglet/app/cocoa.py

Lines 184 to 186 in a728a77

def nsapp_stop(self):
"""Used only for CocoaAlternateEventLoop"""
self.NSApp.terminate_(None)

You could try replacing it with this code instead:

    def nsapp_stop(self):
        """Used only for CocoaAlternateEventLoop"""
        self.NSApp.stop_(None)

        if self.timer:
            self.timer.invalidate()
            self.timer = None

        if self.appdelegate:
            self.appdelegate.dealloc()
            self.appdelegate = None

@abanuelo
Copy link
Author

abanuelo commented May 7, 2024

That's correct @caffeinepills the alternate loop never gets executed following a closure of the pyglet window after a pyglet.app.run(). If we wanted to add that functionality to be able to loop a pyglet.run.app(), would it suffice to override the default behavior to run pass instead of triggering a self.exit() call? Something like this a suppose:

def on_window_close(self, window: BaseWindow):
        """Default window close handler."""
        pass

@P-Kaempf
Copy link

I have experienced the same. In my case, the error message tells me that all Python threads are terminated. Here is the error message:
Fatal Python error: PyEval_RestoreThread: the function must be called with the GIL held, after Python initialization and before Python finalization, but the GIL is released (the current Python thread state is NULL)
Python runtime state: initialized

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants