-
Notifications
You must be signed in to change notification settings - Fork 67
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
WIP: Run the core on the main thread. #111
base: master
Are you sure you want to change the base?
Conversation
Oh, and it also freezes the UI when paused in the debugger, because that waits on a semaphore (condition variable in my branch). Sigh… I really should try the other approach. |
Going back to this – unfortunately, I don't think rendering off the main thread is feasible with SDL video (i.e. without the vidext). In this Stack Overflow post, a poster using Linux got X server errors when trying to render off thread, and 'solved' it by calling So I do think this patch might be the best approach, even if it's a bit icky. The debugger, for its part, can be fixed to pump the event loop so it doesn't freeze the UI when paused. For the record, potential alternatives include:
By the way, I think there's also a minor issue with the vidext, where the OpenGL context is obtained from Qt. Qt explicitly supports off-thread rendering – but it expects a |
I just tried your patch. It looks that non vidext mode is broken. In vidext mode UI can freeze when I for example open ROM from external hard drive that needs some time to wake up. Before, unpacking ROM was running in other thread so that was not an issue. Opening some dialogs will freeze/pause emulation, but some, like cheats dialog doesn't pause. I do like that it pauses emulation, I wanted to do something similar but when focus is lost. For X11, there used to be a code that called X11InitThreads via ctypes before Qt app is created, then it was later changed to use Qt::AA_X11InitThreads attribute, but that was for Qt4 http://doc.qt.io/qt-4.8/qt.html , now in Qt5 it is still used but docs say that it is obsolete http://doc.qt.io/qt-5/qt.html . I tried also to switch to QOpenGLWidget now that QGLWidget is deprecated #90 . I didn't check to see if getProcAddress is now added to PyQt for QOpenGLContext . Maybe newer OpenGL widget can help, a lot of things work differently with new widget. What exactly are the issues in cocoa? I usually just try in OS X in vmware when I pack binaries, but cannot test everything in VM. |
Have you tested QOpenGLWidget with GLideN64? I don't think it will work. QOpenGLWidget renders into a Framebuffer object, which conflicts with GLideN64. You'll probably need to use one that renders onto the native window, like QOpenGLWindow |
@loganmc10 Just tried, you are right, it doesn't work. If native window must be used I guess QGLWidget is fine then, except that it is deprecated. |
Not sure if QMainWindow can be replaced with QOpenGLWindow (to add menus and statusbar), if that can work that is also an option. But again, only rice plugin can work correctly with vidext and resizing, for other plugins you need to stop ROM, resize, then start again. |
You can treat QOpenGLWindow like a widget using QWidget::createWindowContainer(). You create like QOpenGLWindow like:
And then use the "container" widget like you would any other widget, you can put it inside a QMainWindow. I'm not sure if this works in PyQt but it works in C++ |
(Instead of using a worker thread as is done currently.)
Why would you want to do that? To fix no-vidext mode.
In mupen64plus-core, main_check_inputs calls SDL_PumpEvents. SDL_PumpEvents checks if there is a SDL_VideoDevice active - which in this case is only be true when running without vidext - and if so, calls the video backend's PumpEvents. On Mac, that's Cocoa_PumpEvents, which tries to pump the Cocoa event loop, which promptly crashes because you're only supposed to do that from the main thread.
According to the SDL FAQ, it's not just SDL_PumpEvents that should be called on the main thread, but all video functions:
So to make this correct, the core's no-vidext code (that uses SDL video) would have to be modified to do everything asynchronously on the main thread. I think that would be possible and nice to have, but in lieu of doing all the work for that, here's a patch to just run the core on the main thread.
I've verified on Mac that the UI is still usable while playing, in both vidext and no-vidext mode. But I haven't tested this on other platforms at all.
Caveats:
On Mac, opening a menu does its own "synchronous loop that pumps events" thing - it pumps events, but doesn't return to the code that sent it the menu-opened event until the menu is closed. So opening a menu causes emulation to freeze. While unintended, I'm not sure this behavior is actually undesirable, since the user probably opened the menu to select pause or stop anyway. Still, it suggests this approach is not optimal in the long term, and there may be similar or worse side-effects on other platforms.
In vidext mode, the script has the opportunity to call QCoreApplication.processEvents explicitly on each frame, but in no-vidext mode, it relies on the assumption that the core's SDL_PumpEvents also pumps Qt events, because they both run on top of the platform's native event loop. This assumption is true on Mac, and my guess is that it's also true on other platforms, but I haven't tested it. If it doesn't work somewhere, I guess the worker could be changed to support both modes, either running as a thread or borrowing the main thread.