JDK-8210547[linux] Uncontrolled framerate, general frame sync/over-calculating animations
Michael Zucchi
notzed at gmail.com
Thu Sep 25 00:48:48 UTC 2025
Hi Kevin,
On 23/9/25 01:02, Kevin Rushforth wrote:
> Hi Michael,
>
> Welcome to the openjfx-dev list. We've not ever been able to reproduce
> this on any of our systems. It seems likely that it is specific to
> certain graphics drivers. We do all our testing on Ubuntu Linux and
> Oracle Linux (which is based on RHEL), so it's also possible we are
> testing with different drivers even for the same card.
>
Thanks, and I've subscribed to the dev list. It just seemed to be full
of patch discussion so I wasn't sure where to post.
Indeed I saw on the bug nobody could recreate it. Weird. I tried
Oracle Linux 10 on my laptop but I couldn't get it to load the
modesetting driver and boot (incl the official amd driver). With ubuntu
25 vanilla i'm getting the same unthrottled framerate as on my other
systems. I was hoping this wasn't the case so I could see why you
weren't seeing this, so I'll try the other desktops in-case it's
related to the compositor but it's going to take a while as i'm using a
usb stick and ubuntu installation seems very disk heavy in ways every
other linux isn't.
I've attached a standalone example - it runs about 2000fps on one system
when it's down to 1 window. It's intentionally updating each pulse
ignoring the 'frac' value so the pulse timing can be visualised.
I don't know if it's useful but this is sample output from quantum.debug:
QT.postPulse#(95891966861546): DROP : TAPN
QT.endPulse: 95891966882376
QT.vsyncHint: postPulse: 95891967385262
QT.postPulse@(95891967391984): TAPN
QT.endPulse: 95891967429776
QT.vsyncHint: postPulse: 95891968031510
QT.postPulse@(95891968039475): TAPN
QT.endPulse: 95891968072438
QT.vsyncHint: postPulse: 95891968663842
QT.postPulse@(95891968671827): TAPN
QT.endPulse: 95891968696373
This last basic sequence repeats a dozen or so times times until a DROP
: TAPN again
Note that each postPulse() is about 650uS apart.
> If you have a reliable patch for the bug, you can submit a PR although
> we will need to find a way to test it. See the CONTRIBUTING [1]
> guidelines for what you will need to do in order to contribute.
>
I spent a frustrating hour or so trying to log into an oracle account I
forgot I had, then creating a new one which I also can't log into ("A
federated user can't perform local authentication.") so I can't sign the
OCA for now (if it ever gets to that point).
I looked more at the latest code (without the vsync patch).
Commenting out makeCurrent(null) in ES2SwapChain.present() throttles the
pulse but only if there is a single window (i.e. because the context
never changes). Perhaps this is a driver difference, and causes
glxswapbuffers not to throttle even with double buffering on the
rendering context. makeContext is quite expensive (a few ms), so i'm
surprised it is called every render pass (apart from the obvious of
being easier to implement with a single render thread). Adding a
glFinish() immediately after swapbuffers almost works but it halves the
framerate when too many windows (>2) are active because it's performed
per-window and not per-pulse.
Secondly, tracing PaintCollector.done() calls toolkit.vsyncHint() which
calls postPulse() whose logic will always fire a new pulse when an
animation is active (i.e. the Transition in the example). Is this really
the expected behaviour here? vsyncHint() seems to be to perform a vsync
not to fire another pulse. Just commenting out vsyncHint() fixes the
poor throttling but then it runs quite jittery due to timing via
gdk_thread_timeout.
I added some time measurement to ES2SWwapChain.present() with a single
window and it confirms that this is where the throttling or not occurs -
with makeCurrent(null) removed 2 frames are presented very quickly then
swapBuffers() blocks to match the display (and also means rendering is 2
frames ahead). With it added in it just runs asynchronously and returns
very quickly. I was hoping to confirm against a 'working' platform but
alas so far.
TBH the throttling is important but I was also curious about addressing
the jitteriness due to using gdk_thread_timeout, it seems vsyncHint() is
meant for that but there doesn't seem to be any linkage between that and
the pulse timing esp since the 'hint' isn't vsync-synced, so it just
ends up firing another pulse immediately or pausing the timer if no
animation is active.
I'm still thinking of fixes, perhaps a more accurate pulse timer is
enough (and basically ignore vsyncHint) but it will have to be platform
specific. I will have to study the other backends a bit more first as well.
Are there plans for a vulkan backend? That might solve/move the
problem. I've seen in mentioned in the past but I can't find anything
on the web about anything concrete.
Regards,
Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20250925/c9fc81d5/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: throttle.java
Type: text/x-java
Size: 2151 bytes
Desc: not available
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20250925/c9fc81d5/throttle-0001.java>
More information about the openjfx-dev
mailing list