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

Surface multiphase init #3354

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

oddbookworm
Copy link
Member

Since disabling the GIL on singlephase initialization requires the use of PyUnstable_* calls, I would like to make use of multiphase initialization whenever possible. Here is a tentative implementation for an initial port for pygame.Surface. Note that this is just for moving over to multiphase initialization and has nothing to do with free-threading. This should not affect current behavior in any way to the best of my understanding

@oddbookworm oddbookworm added Code quality/robustness Code quality and resilience to changes Surface pygame.Surface labels Feb 28, 2025
@oddbookworm oddbookworm requested a review from a team as a code owner February 28, 2025 19:41
static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT,
"surface",
DOC_SURFACE,
-1,
0,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this change? for now I believe it should still be -1 right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ll double check, but it wouldn’t run for me with -1 because -1 is incompatible with subinterpreters, and multiphase implicitly assumes subinterpreter compat (and I actually forgot to figure out what the actual value should be)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's what I thought

❯ python -c "import pygame"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import pygame
  File "C:\Users\andre\Projects\pygame-ce\src_py\__init__.py", line 166, in <module>
    import pygame.display
SystemError: module pygame.surface: m_size may not be negative for multi-phase initialization

@damusss
Copy link
Member

damusss commented Mar 1, 2025

Hi Andrew. Could you explain to me what this singlephase/multiphase initialization and subinterpreters thing is about? Or if it's easier, where can I properly read about it? I'm uninformed about the topic.

@oddbookworm
Copy link
Member Author

Hi Andrew. Could you explain to me what this singlephase/multiphase initialization and subinterpreters thing is about? Or if it's easier, where can I properly read about it? I'm uninformed about the topic.

Here’s the pep for multi phase
single phase docs
multi phase docs

the reason I want to make this change is because of free threading. Disabling the GIL at a module level in single phase requires the use of unstable API, which can (and probably will) change on us at some arbitrary Python minor version update. Disabling the GIL at a module level in multi phase is as simple as defining a slot

@oddbookworm
Copy link
Member Author

subinterpreters is another topic. The only reason it’s brought up here is because multiphase makes some assumptions that need to be handled for it

@oddbookworm
Copy link
Member Author

Properly handling subinterpreters should be left off for a future pull

Copy link
Member

@ankith26 ankith26 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the PR! 🎉

I'm still not a 100% clear on all refcounting aspects of this PR, but these are module level objects that are supposed to be immortal anyways, so overcounting references should practically be fine :)

@oddbookworm
Copy link
Member Author

I'm still not a 100% clear on all refcounting aspects of this PR, but these are module level objects that are supposed to be immortal anyways, so overcounting references should practically be fine :)

Which part is confusing?
Feel free to ping me on discord if that's easier

c_api[1] = pgSurface_New2;
c_api[2] = pgSurface_Blit;
c_api[3] = pgSurface_SetSurface;
apiobj = encapsulate_api(c_api, "surface");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a strong reference presumably, so my hunch is that it should be decref'd because now PyModule_AddObjectRef is not stealing a reference

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, as I said before it's probably not a big deal

@Starbuck5
Copy link
Member

I'm also uncertain about the ref counting in this PR, with PyModule_AddObjectRef.

Reading over the multiphase init documentation it mentioned PyModule_AddObjectRef, so maybe Andrew you used it because it was mentioned there?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Code quality/robustness Code quality and resilience to changes Surface pygame.Surface
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants