-
-
Notifications
You must be signed in to change notification settings - Fork 798
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
ENH Support SDL-based packages and add pyxel #3508
Conversation
This reverts commit 60e0026.
i'd be really curious to compare sizes when adding this I suspect SDL2 brings most of that stuff already in, but those params could help a lot of others packages like pyopengl(es) / moderngl / raylib / harfang / Panda3D and probably others. |
Sounds great. USE_WEGBL2 flag will add library_webgl2.js (46.2 KB), and other flags will not add additional javascript files, so I think the size increase would be quite small. |
i was a bit wrong including raylib this one need another binding but 46K seems great for such openness |
Hi Y'all - Jeff here on the PyScript team. I'm quite excited about the possibility of using Pyxel (and other SDL-based packages) in the browser - having built a copy of Pyodide from this branch and tried out Pyxel, I'm hugely impressed by how much just works. And the ability for Pyxel to interact with the DOM, window events etc opens up a ton of really exciting possibilities. If there's anything I can help with on this - testing, feedback, writing docs/tests, actual code - I'd be happy to contribute if it would be helpful. |
@szabolcsdombi Thanks for sharing your glue code! This is ready to be reviewed now. I think we can improve multi canvas issues, GLFW support, and other things incrementally as a follow up as @pmp-p mentioned. For now, this PR adds support for pyxel so I think it is sufficient for this PR. |
```{admonition} This is experimental | ||
:class: warning | ||
|
||
SDL support in Pyodide is experimental. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would still be nice to standardize our stability guarantees a little more. (No action needed.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes indeed. I'll add some more explanation that we are depending on the non-documented behavior of Emscripten / SDL libraries.
src/core/pyproxy.ts
Outdated
if (e && e === "unwind") { | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this might be handled better in API.fatal_error
(we already handle exit there). Then all of these could change to
API.fatal_error(e);
return; // in case it's not actually a fatal
since it is possible to execute arbitrary Python code from any of the other entrypoints in this file. Of course fatal_error
should also change it's name to probable_fatal_error
. We already handle os._exit()
calls there so the name isn't quite accurate anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, is this... really okay? This seems pretty disturbing as a behavior.
- Does it actually happen?
- Does it really not break Python interpreter invariants?
The linked issue is pretty vague.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this might be handled better in API.fatal_error (we already handle exit there). Then all of these could change to
Yeah, I also think putting this into API.fatal_error
would be better. For now, there are some places that assume API.fatal_error
will not return, so I think we should fix that first.
Does it actually happen?
Yes, it happens. (edit: fixed link)
Does it really not break Python interpreter invariants?
I believe so...? It is just a JS exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe so...?
Does Pyxel have extra logic to unwind the Python stack?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, pyxel just ignores when it gets "unwind".
Okay, I guess I should do some more experiments and be more careful about this. I'm not sure what can happen on Python interpreter side when Emscripten throws an exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I see instead is:
Stack (most recent call first):
File "<exec>", line 8 in g
File "<exec>", line 5 in f
File "<exec>", line 10 in <module>
File "/lib/python311.zip/_pyodide/_base.py", line 310 in run
File "/lib/python311.zip/_pyodide/_base.py", line 468 in eval_code
so there are some "dead frames" that are left on the Python stack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the check, then I think we should do
- unwind Python stack frames manually (not sure this makes sense), or
- tell people to not use
simulate_infinite_loop=true
when usingemscripten_set_main_loop
.
@pmp-p Do you have some idea about this? I think pygbag also use simulate_infinite_loop option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, by the way, can we actually call that "dead frames"? Conceptually this runs infinite loops in that frame.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we actually call that "dead frames"?
I think what you'll see if you call another Python function is that the new frames go on top of the old ones and the old frames are never re entered, and all objects owned by them are leaked. So I believe they are actually leaked frames. But I could be wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what you'll see if you call another Python function is that the new frames go on top of the old ones and the old frames are never re entered, and all objects owned by them are leaked.
Yes, indeed the new functions go on top of the old ones.
Okay, but the issue is that I think the old frames are used inside the loop so we can't clear those frames. So maybe we should let users explicitly cancel the loop and maybe block other commands until the loop is running. I think this is going to be more complicated than I thought, so I'll open a separate issue.
|
||
assert(() => pyodide._module.canvas === canvas); | ||
assert(() => pyodide.canvas.getCanvas2D() === canvas); | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we maybe clear it after so there aren't side effects?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched to selenium_standalone to avoid side effects of the feature flag.
Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com>
for more information, see https://pre-commit.ci
So what's the situation with this PR for the release? Do we merge as is, accept that stack traces are not going to be unwound correctly after calling |
Personally, I would like to include this in 0.23.0, as I believe some folks would want to try this. But it is not a strong opinion, so if one of the other maintainers disagrees, I am okay to postpone this. Maybe I can finish #3705 before releasing 0.23.0, but I can't guarantee it ( I'll be a bit busy for the next couple of weeks :( )
Right, it doesn't affect existing users. |
Fine with me to merge this as is. @hoodmane ? |
I think we should defer this to |
Well, the problem is that it links more things into the main module and potentially impacts error catching depending on the outcome of the discussion, so if we put it in the 0.23.1 and it creates some changes of behavior for existing apps, that's not very reasonable for a bug fix release IMO. While if we put in the 0.23.0 even if has known issues when using SDL apps, and we fix those in 0.23.1 it might be better. Otherwise, it would mean 0.24 which is still far way. Are your concerns in #3508 (comment) about this creating regressions for existing users, or that it would be suboptimal for users trying this functionality? In the latter case, I would say that the experimental tag could justify some of it. |
I am okay with merging if we include some obvious warning that it doesn't work. |
Maybe we could put it behind a feature flag or something? Like the way chrome ships broken code behind "experimental: unstable wip feature" flags... |
Without unwind support, I think any application that runs for long enough will eventually fill the interpreter with dead frames so that any attempt to run code raises a stack overflow error. |
Something like:
and then in, } catch (e) {
if (API._skip_unwind_fatal_error) {
API.maybe_fatal_error(e);
} else {
API.fatal_error(e);
}
return;
} finally { ? We can always adjust the wording later in the docs, the main this to agree on the feature flag mechanism. |
Looks great! |
Thanks, for finishing this! |
Description
This adds SDL-based package support to Pyodide and adds pyxel as a PoC. Most of the troubleshooting is done by @kitao and pyxel devs, a big thanks to them.
This is on top of #3505
Before (in #3505):
After:
Module.canvas
, but the canvas attribute is not set automatically (which makes sense as we don't output any HTML), so it is the user's job to set it manually.For now, I am thinking of just mentioning it in the FAQ entry, "you need to set pyodide._module.canvas = ...". But it would be probably nice to have an API to set canvas, as pyodide._module is a private attribute.
Checklists
Demo
https://ryanking13.github.io/pyodide-pyxel-test
(mostly borrowed from the pyxel repository: https://github.com/kitao/pyxel/tree/main/wasm)