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

Turn off vsync throttling when macOS hardware sleeps #927

Merged
merged 3 commits into from
May 21, 2024

Conversation

elijah-semyonov
Copy link
Contributor

@elijah-semyonov elijah-semyonov commented May 17, 2024

Speculative fix for a freeze issue.

@elijah-semyonov elijah-semyonov merged commit 5058bbc into master May 21, 2024
5 checks passed
@elijah-semyonov elijah-semyonov deleted the es/macos-fix-freeze-after-sleep branch May 21, 2024 07:36
Copy link
Collaborator

@igordmn igordmn left a comment

Choose a reason for hiding this comment

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

Thanks!

I left important comments need to be discussed.

[self onVSync];
}

- (void)systemDidWake:(NSNotification *)notification {
Copy link
Collaborator

@igordmn igordmn May 21, 2024

Choose a reason for hiding this comment

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

When the system wakes up, we need to notify the window to redraw the content. If system calls the AWT function paint(), it will redraw it. But can we guarantee that? If not, we should send a signal to AWT here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

It seems the fix isn't about disabling redrawing, but about disabling vsync. In this case, no need to notify. But will we have unlimited FPS, and should stop drawing in case of sleeping?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The issue is about deadlock on the conditional variable encpsulating vsync state. I can't reproduce that so my speculation is to destroy this mechanism temporarily while the device is sleeping.
I have an idea that have some really funny race-condition, where the logical screen for the window changes mid-flight due to some OS-level reconfigurations (flickering when connecting a display/waking up), so we wait on vsync from the screen which no longer exists/and AppKit didn't gracefully changed the screen to the existing one, but I have no idea currently how to fix that so I'd better try this solution and see if it fixes the issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Potentially, it can indeed cause discarded drawables (because of redundant redraws, the initial issue that vsync mechanism fixed) if multiple were presented during a single hardware vsync after the the sleep notification, but that's an edge case that I bet will not affect the users

Copy link
Contributor Author

Choose a reason for hiding this comment

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

macOS has less strict policy about drawables management and metal commands issuing from what I've observed, so stopping drawing altogether doesn't seem to be needed for correctness. Plus the AWT logic will also suspend at some point, hopefully.

Copy link
Collaborator

Choose a reason for hiding this comment

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

vsync also prevents unlimited FPS, which can load GPU/CPU. Do this code run for some time after sleeping?

@SergeevPavel
Copy link
Collaborator

I've noticed one more strange thing, not sure that it's related with this changes, but anyway. Usually we call performDraw() and waiting for vsync on our special blocking dispatcher. But in the problematic stack traces I see that we came from JComponent#paint and through redrawImmediately we call performDraw and block EventDispatchThread until we get vsync. I'm not sure how often Swing calls the paint method, but blocking (not suspending) on EventDispatchThread may lead to poor performance because it's used not only for rendering but also for user event processing and performing callbacks that update UI related state.
So, the question, do we really need to wait for vsync when JComponent#paint is called? May we draw without waiting for vsync or maybe at least unblock paint and offload blocking to blockingDispatcher?

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

Successfully merging this pull request may close these issues.

None yet

3 participants