RFR: 8210547: [Linux] Uncontrolled framerate [v2]
notzed
duke at openjdk.org
Thu Oct 9 04:22:23 UTC 2025
On Sat, 4 Oct 2025 15:19:32 GMT, Thiago Milczarek Sayao <tsayao at openjdk.org> wrote:
>> As Michael Zucchi pointed out on the mailing list, the high framerate occurs because `glXSwapBuffers() `operates asynchronously. To ensure proper synchronization, you can call `glFinish() `afterward, which blocks until the buffer swap is fully completed. However, when using `glXSwapIntervalSGI`, the swap interval setting applies globally rather than per drawable. In contrast, `glXSwapIntervalEXT` provides per-drawable control, allowing finer-grained vsync behavior.
>>
>> I don't know if there are scenarios when the unlimited frame rate is needed - if so we should provide a option.
>>
>> See [https://wikis.khronos.org/opengl/Swap_Interval](https://wikis.khronos.org/opengl/Swap_Interval)
>>
>> It also selects the correct visual for transparency which needs to be depth = 32 for X11.
>
> Thiago Milczarek Sayao has updated the pull request incrementally with one additional commit since the last revision:
>
> Call glXSwapIntervalEXT or glXSwapIntervalSGI if not null
Nice, I (Michael Z) can confirm it fixes the frame throttling here, although in a simple animation all rendered frames have a pulse-presentation latency of 33ms -- which is somewhat better than the 48ms previously.
I've been doing some testing of the pulse-presentation latency, taking timestamps of the start of the pulse, the end of the render (before glXSwapBuffers), and the GL_TIMESTAMP of when glXSwapBuffers() is processed (via glQueryCounter()). Plus tracking the pulse number all the way through so they can be matched. This is some of the output with the patch:
event pulse-submit present
pulse 1050 17484397796
present 1048 17467793037 17484194371 - +16.697 +33.098
pulse 1051 17501064359
present 1049 17484490371 17500860741 - +16.782 +33.152
pulse 1052 17517726363
present 1050 17501155852 17517524593 - +16.758 +33.127
pulse 1053 17534403585
(This is in logging order, not temporal)
As a comparison using the existing SwapIntervalSGI and calling glFinish() after all scenes have rendered results in a pulse-presentation latency of 16.7ms instead. Adding the glFinish() to the SwapIntervalEXT version has no effect.
pulse 1050 17478236976
present 1048 17461465333 17461674222 - +16.569 +16.778
pulse 1051 17494927765
present 1049 17478075556 17478273482 - +16.443 +16.641
pulse 1052 17511531058
present 1050 17494771852 17494973482 - +16.535 +16.737
pulse 1053 17528240031
??? I don't know why they'd be different given they both have the same order of pulses, but the timing code is the same.
For the curious, [I blogged about the timings I did yesterday](https://www.zedzone.au/post/0199c6c0edb7), I haven't added any plots with this patch but they look the same as "Build 2" but with another frame of latency to the present times (around 33 vs 16-17ms).
> I don't know if there are scenarios when the unlimited frame rate is needed - if so we should provide a option.
Well if prism.vsync=false it wont call swapinterval and will just run at the pulse rate, plus there's javafx.animation.fullspeed?
-------------
PR Comment: https://git.openjdk.org/jfx/pull/1929#issuecomment-3384029282
More information about the openjfx-dev
mailing list