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