<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<p>It's a constant value for all handler invocations for a given
frame, I think that part is correct. It should not matter that a
later handler is doing its calculations for the next frame at a
different point in real time; it would still be doing calculations
for the next frame, and as long as it completes those before the
next frame is rendered it will be "on time".</p>
<p>So if I have two handlers, A and B, and A is called at (real)
time X, and B is called at (real) time X + 200 ns, they both
should get a "now" value that corresponds to the next frame to be
rendered -- this doesn't have to be derived from System.nanoTime
at all. It only needs to start at some value and be incremented
for each frame rendered (including missed frames). AnimationTimer
is not documented to say that the value is derived from nanoTime
-- it is just happenstance that the value currently used
corresponds closely to System.nanoTime.</p>
<p>--John<br>
</p>
<div class="moz-cite-prefix">On 29/08/2024 20:53, Andy Goryachev
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:BL3PR10MB618523CFFAEA59ADD73C600FE5962@BL3PR10MB6185.namprd10.prod.outlook.com">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="Generator"
content="Microsoft Word 15 (filtered medium)">
<style>@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}@font-face
{font-family:Aptos;
panose-1:2 11 0 4 2 2 2 2 2 4;}@font-face
{font-family:"Iosevka Fixed SS16";
panose-1:2 0 5 9 3 0 0 0 0 4;}@font-face
{font-family:"Times New Roman \(Body CS\)";
panose-1:2 11 6 4 2 2 2 2 2 4;}p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:10.0pt;
font-family:"Aptos",sans-serif;}span.EmailStyle19
{mso-style-type:personal-reply;
font-family:"Iosevka Fixed SS16";
color:windowtext;}.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;
mso-ligatures:none;}div.WordSection1
{page:WordSection1;}</style>
<div class="WordSection1">
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">This
might be slightly off-topic, but I noticed that instead of
computing 'now' time for AnimationTimer.handle(long) just
before calling the actual handler, we do compute it once
before sending to possibly multiple handlers. Each
subsequent invocation produces progressively larger
discrepancy (AbstractPrimaryTimer:264).<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Does
not explain the issue John raised though.<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<div id="mail-editor-reference-message-container">
<div>
<div>
<div
style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal" style="margin-bottom:12.0pt"><b><span
style="font-size:12.0pt;color:black">From:
</span></b><span
style="font-size:12.0pt;color:black">openjfx-dev
<a class="moz-txt-link-rfc2396E" href="mailto:openjfx-dev-retn@openjdk.org"><openjfx-dev-retn@openjdk.org></a> on behalf of
Michael Strauß <a class="moz-txt-link-rfc2396E" href="mailto:michaelstrau2@gmail.com"><michaelstrau2@gmail.com></a><br>
<b>Date: </b>Thursday, August 29, 2024 at 11:45<br>
<b>To: </b><br>
<b>Cc: </b><a class="moz-txt-link-abbreviated" href="mailto:openjfx-dev@openjdk.org">openjfx-dev@openjdk.org</a>
<a class="moz-txt-link-rfc2396E" href="mailto:openjfx-dev@openjdk.org"><openjfx-dev@openjdk.org></a><br>
<b>Subject: </b>Re: Bug: Times passed to
AnimationTimer should not fluctuate<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt">Yes,
that makes sense. In any case, we shouldn't be using
a system<br>
timer, but simply record the timestamp at v-sync,
and then pass this<br>
precise timestamp to all AnimationTimers. It
shouldn't matter when<br>
AnimationTimers are invoked between frames, as long
as the timestamp<br>
corresponds to the v-sync signal. (Well, unless the
timer callback<br>
measures its own time, which it shouldn't do.)<br>
<br>
<br>
On Thu, Aug 29, 2024 at 8:20</span><span
style="font-size:11.0pt;font-family:"Arial",sans-serif"> </span><span
style="font-size:11.0pt">PM John Hendrikx
<a class="moz-txt-link-rfc2396E" href="mailto:john.hendrikx@gmail.com"><john.hendrikx@gmail.com></a> wrote:<br>
><br>
> I think they're a bit separate. Even with
VSync, the time it takes to kick the FX thread in
action is still going to be between 0-30ms. If it
then passes `System.nanoTime()` to the
AnimationRunnables, you're basically saying that
they should render a frame at the precise time of
VSync-Time + random time it took to schedule the FX
thread... suffice to say that the extra accuracy of
the more accurate VSync timer (just like my far more
accurate timer) is made completely redundant by the
jitter introduced by the scheduler.<br>
><br>
> This brings me back to my original point: we
should not be passing `System.nanoTime()` to
AnimationRunnables. Passing `System.nanoTime()` is
basically asking to create a frame with a time index
that will NEVER be rendered, so why are we asking
Animations to use this value for calculating
animation locations/offsets/sizes ?<br>
><br>
> This problem is also present on Mac and Linux,
just less noticeable because their schedulers
generally react within 0-2 ms (vs 0-30 ms on
Windows). 2 ms is "close enough" to the most
commonly used frame rates (60 fps, at 16.667 ms per
frame), but on Windows it can practically be a two
frame difference.<br>
><br>
> Even in the absence of V-sync, when JavaFX
arbitrarily picks 60 Hz as its refresh frequency,
the times passed to AnimationTimer should be
multiples of 16.667 ms, not 16.667 ms + however long
it took to wake up the FX thread. In other words
this code in AbstactPrimaryTimer:<br>
><br>
> private long nextPulseTime = nanos();<br>
><br>
> private long lastPulseDuration =
Integer.MIN_VALUE;<br>
><br>
> @Override<br>
><br>
> public void run() {<br>
><br>
> if (paused) {<br>
><br>
> return;<br>
><br>
> }<br>
><br>
> final long now = nanos();<br>
><br>
> recordStart((nextPulseTime - now) / 1000000);<br>
><br>
> timePulseImpl(now);<br>
><br>
> recordEnd();<br>
><br>
> updateNextPulseTime(now);<br>
><br>
> // reschedule animation runnable if needed<br>
><br>
> updateAnimationRunnable();<br>
><br>
> }<br>
><br>
> ...would be far better if it passed
"nextPulseTime" to `timePulseImpl` (which eventually
calls the AnimationRunnables) instead of "now".<br>
><br>
> Note: this is assuming the adaptive pulse flag
is disabled. If it is enabled, nextPulseTime won't
be a nice multiple of the frame rate -- so when this
is enabled we may want to round it up/down before
passing it to the AnimationRunnables.<br>
><br>
> Note 2: you can **already** achieve far
smoother animation even on Windows by rounding the
value you get passed in to a multiple of
1/frameRate. This only works when you have access to
the this time. It won't solve Timeline calculations
-- they will still calculate positions and values
for frames that will never exist, subject to FX
thread scheduling jitter...<br>
><br>
> --John<o:p></o:p></span></p>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</body>
</html>