Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: query the system's current FPS setting  (Read 11222 times)

0 Members and 4 Guests are viewing this topic.

kfj

  • Newbie
  • *
  • Posts: 19
    • View Profile
query the system's current FPS setting
« on: April 25, 2017, 10:43:59 am »
Hi group!

I'm looking for a portable way to query the FPS (frames per second) setting of the system my SFML program is running on. So I am *not* looking for a way to measure how many FPS my program is producing, but I want the currently active setting for the display driver. My program is driven by the vertical sync and can adapt it's computational load to produce frames faster or slower, but to get an idea how much time it has to produce a frame, it should know what the system is expecting: If the graphics unit feeds 60 FPS to the monitor, my time budget to render a frame is obviously smaller than it is when it's using 50 or even 30 FPS if I want to supply it with frames at the currently set rate.

While there may be ways to get the information via the system settings, I'd like to do a query from *inside* my program which will work on all systems SFML supports, so that it's portable. I suspect the information should not be too hard to extract - ideally I'd like it to be incorporated, for example, into the sf::VideoMode structure, or to be returned by a simple getter function.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: query the system's current FPS setting
« Reply #1 on: April 25, 2017, 11:18:16 am »
Quote
I suspect the information should not be too hard to extract
The refresh rate of monitor(s) is not hard to extract, but the graphics driver v-sync settings... I don't think you can.

One solution is to measure the duration between two consecutive (empty) frames when the application starts.

There are probably other solutions that don't involve to know the frame duration, but without knowing exactly what you do, it's hard to say more.
Laurent Gomila - SFML developer

kfj

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: query the system's current FPS setting
« Reply #2 on: April 25, 2017, 11:47:05 am »
The refresh rate of monitor(s) is not hard to extract

This is precisely what I want. I'm not sure if one can query the refresh rate of the monitor itself, but I'd like to get the rate at which the system is sending frames out to it. If you know of a portable way of extracting the refresh rate of monitor, please let me know!

Quote
One solution is to measure the duration between two consecutive (empty) frames when the application starts.

I'd like to avoid trickery like this - and if the information is easy to get, why choose a complicated way of getting it  ;)

Quote
... but without knowing exactly what you do, it's hard to say more.

I'm writing an image viewer allowing all kinds of manipulations like zoom, pan and rotate, and I animate these manipulations smoothly, relying of a fixed frame rate, and the vsync to display every frame in time. I can adapt rendering times by rendering to a smaller frame, which I let SFML display enlarged by using a view. This way, may (CPU-based) rendering time can be adapted to what the system can handle, while the upsacling of the small frame which I've rendered is done via SFML/openGL and takes next to no time. When at rest after animating the zoom, pan, etc, I render to full resolution again.

To keep this process running smoothly, I render in a separate thread and buffer a few frames. This way, even if the rendering times vary from frame to frame I don't get stutter because with a few frames buffered it all averages out. Works like a dream, and the latency is so small it doesn't matter - after all, I'm writing an image viewer, not a shooter.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: query the system's current FPS setting
« Reply #3 on: April 25, 2017, 11:51:40 am »
Quote
This is precisely what I want. I'm not sure if one can query the refresh rate of the monitor itself, but I'd like to get the rate at which the system is sending frames out to it.
The refresh rate of monitor could easily be added to sf::VideoMode; I think all back-ends already have this information, it's just a matter of exposing it in the public API.

But I don't think it is relevant. Don't forget that the GPU driver is in between, and can do whatever it wants: send a frame at the same rate, at half this rate, or as fast as it can, etc. And I don't think you can retrieve these driver settings.
Laurent Gomila - SFML developer

kfj

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: query the system's current FPS setting
« Reply #4 on: April 25, 2017, 12:02:42 pm »
The refresh rate of monitor could easily be added to sf::VideoMode; I think all back-ends already have this information, it's just a matter of exposing it in the public API.
Plase do!
Quote
But I don't think it is relevant.
I beg to differ: It would be a good starting point. Currently I am using some default which seems sensible, assuming 50fps. If I had information from the system, I could use that as the starting point and with a bit of luck this starting point is better than guessing a 'plausible' value.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: query the system's current FPS setting
« Reply #5 on: April 25, 2017, 01:06:41 pm »
Quote
I beg to differ: It would be a good starting point.
Have you read what I said about the GPU driver?
Laurent Gomila - SFML developer

kfj

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: query the system's current FPS setting
« Reply #6 on: April 26, 2017, 08:42:02 am »
Quote
I beg to differ: It would be a good starting point.
Have you read what I said about the GPU driver?
I did read that. Be assured, I'm glad that you take the time to give good advice and I carefully read everything you write. Let me explain in more detail what my problem is:
On my system (Kubuntu 16.10 running on an Intel(R) Core(TM) i5-4570, no graphics card) I have lots of problems with stuttering. The only way I have found so far to get the system displaying my graphics smoothly is by using setVerticalSyncEnabled(true) and making sure I call display() in time. With the method I have outlined above, I need an estimate of the time budget I have to come up with new frames so I can adapt my processing time if my calculations take too long. I would like to base my estimate on the currently active FPS setting, which, as you say, is easy to extract but not available in the public API. All I'd like to see is a way to query this setting, never mid the driver. What the driver does or does not do to the stream of frames is outside my control anyway, but it can be tweaked by the user to look good on their hardware.
I have timed the time difference from one call to display() to the next and found that, at least on my system, the times do eventually settle on an average which is close to the figure I search, but extracting it this way means looking at the frame-to-frame times over some time, waiting for them to stabilize and then extract an estimate. It would be much easier to have a value to start out with, namely the 20ms for 50fps or 16.7 ms for 60fps etc..
Maybe it's not a good idea to put the value inside the sf::VideoMode structure, but a simple getter function à la sf::getCurrentFPSSetting() would not harm anyone, especially if it says in the documentation that there is no garantee that the system will actually display frames at this rate and that it is merely the setting in the window manager.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: query the system's current FPS setting
« Reply #7 on: April 26, 2017, 11:01:47 am »
I don't think you understand what I'm trying to explain. No matter how often your monitor refreshes its pixels (*), if the graphics card decides to send frames at a different rate then this value doesn't mean anything for your application. What's important for you is the time between two GPU frames, not between two refresh of the monitor. In my opinion, the refresh rate of the monitor itself is an irrelevant piece of information. If the graphics driver decides to sync at 30 FPS then your target value should be 30, even if your LCD monitor can refresh as fast as 200 Hz.

(*) LCDs don't continuously refresh their pixels like CRTs do. All we can talk about is the minimum time which is needed to switch a pixel from one state to another. So the refresh of the whole screen actually only depends on the graphics driver, the monitor won't physically trigger periodic refresh.
Laurent Gomila - SFML developer

kfj

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: query the system's current FPS setting
« Reply #8 on: April 26, 2017, 11:59:30 am »
I don't think you understand what I'm trying to explain...
But I do! I want precisely the time between two GPU frames. I don't think the graphics driver can even know what the monitor does, and I am not concerned with this datum. I thought the time between two GPU frames is what you set when setting the FPS in the system settings, but I may have misunderstood that bit. I thought the graphics hardware simply produces a signal which the monitor adapts to - or stays black if it can't handle the signal.

So is it possible to query the time between two GPU frames?

I understand and agree that the refresh rate of the monitor is irrelevant. I don't want to know the monitor's refresh rate, I want the time between two GPU frames, if it can be provided.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: query the system's current FPS setting
« Reply #9 on: April 26, 2017, 12:17:11 pm »
Quote
So is it possible to query the time between two GPU frames?
I don't think so. This is specific to the graphics driver (this is not handled by the OS), and there's no API to play with the graphics driver settings.
Laurent Gomila - SFML developer

kfj

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: query the system's current FPS setting
« Reply #10 on: April 27, 2017, 11:19:01 am »
Since the time between two GPU frames seems hard to get, I have now followed your alternative proposal and resorted to taking measurements of the time between successive calls to display(). Just looking at the first two frames did not work for me. So initially I looked at the time differences between all frames in an animated sequence, but I noticed that these values did vary a good deal initially and stabilized only after some time. So now I use this method:

- take the time delta between successive calls to display()
- if the animated sequence has run for at least 25 frames, cumulate the delta
- calculate the time between GPU frames as the average of the cumulated deltas

The value stabilizes after some time, but keeps on fluctuating by a small amount. An alternative would be to use a gliding average, which has the advantage that the value adapts more quickly to a change to the FPS via the system settings, but I think this is too much of a corner case to bother.

I noticed one surprising thing, which shows how apt your comment on the unreliability of settings vs. reality is: the result of my measurements does not approach 16.6 / 20.0 msec for 60 / 50 fps, respectively, but instead converges on ca. 16.0 / 19.5. I think this is a genuine difference, not due to false measurements - to take the times I use std::chrono::system_clock::now(), which should be fairly accurate.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: query the system's current FPS setting
« Reply #11 on: April 27, 2017, 10:08:24 pm »
- take the time delta between successive calls to display()
- if the animated sequence has run for at least 25 frames, cumulate the delta
- calculate the time between GPU frames as the average of the cumulated deltas
Timing a frame is fairly accurate but not great so adding those frame times would cumulate their error.
It would be more accurate - if you need it - to just measure the time after 25 frames have passed and then divide for the average.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

kfj

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: query the system's current FPS setting
« Reply #12 on: April 28, 2017, 06:44:47 pm »
Timing a frame is fairly accurate but not great so adding those frame times would cumulate their error.
It would be more accurate - if you need it - to just measure the time after 25 frames have passed and then divide for the average.
The error does not cumulate because the times I measure actually vary around a fixed value, the GPU frame time (at least I think that is constant!). After many observations, the variations cancel out and the underlying period manifests in the mean. What I'm timing is the time from one call to display to the next; there is nothing to get 'in between'.

I was only omitting the first 25 frames because there the deviation from the true value was often so great that the average initially varied too much, but that was a quick shot. It's a good idea to use the first measurements, but only after some time, as you have suggested. So now I wait until 25 frames have passed before I *use* the average. On my system, it takes a few hundred frames for the value to really stabilize. Thanks for the hint!

sjaustirni

  • Jr. Member
  • **
  • Posts: 94
    • View Profile
Re: query the system's current FPS setting
« Reply #13 on: April 28, 2017, 09:08:14 pm »
I believe that what Hapax meant by error accumulation is the error (inaccuracy) caused by std::chrono, which does accumulate when using multiple measurements.

kfj

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: query the system's current FPS setting
« Reply #14 on: April 29, 2017, 08:45:21 am »
I believe that what Hapax meant by error accumulation is the error (inaccuracy) caused by std::chrono, which does accumulate when using multiple measurements.
It does not, in this case. Let me explain. What we are looking at is a sequence of time points:

{ t0, t1, ...tk }

where the individual times tn are composed of a fixed 'true' time n * dt (dt being the fixed, unvarying GPU frame time) and an arbitrary small error en, where en is never larger than the maximal measurement error (std::chrono's inaccuracy):

tn = n * dt + en

Now we increase k. We have

tk = k * dt + ek

When we take the average a, we get

a = tk / k
a = dt + ek / k

So, after k measurements, the error of the average is precisely ek / k, which, with large k, approaches 0. There is now way for an error to accumulate in this system, the error only depends on the error of the last measurement, divided by the number of total measurements.

I have to eat my words concerning another statement I made, though. I wrote earlier that the average frame time did not come out at 16.6 / 20.0 respectively. This was due to sloppy programming on my part: I stupidly did a std::chrono::duration_cast<std::chrono::milliseconds> on my times, resulting in the value being truncated to an integer millisecond value, which produced the .5 time difference, because my faulty maths sure *did* cumulate. I now changed the code to use std::chrono::duration_cast<std::chrono::microseconds>, assign to float and divide by 1000.0. Lo and behold, the timing is spot on. And it only takes a few frames to stabilize, so 25 is ample for a sample.