简体   繁体   中英

How to set a custom FPS limit on shady engine

I am currently using shady on a 144 HZ monitor and I'm trying to limit the shady world refresh rate to 90 Hz. From my understanding the only way to reduce the FPS is by using the "SetSwapInterval" which cuts the framerate by half or third. Is there anyway other way to reduce the FPS by making a call to shady without using time.sleep() or some other python based timing to achieve this effect?

First it's important to understand: if you update screen content at intervals that are not an integer multiple of the monitor's physical refresh period, you're bound to get temporal artifacts of one type or another. If it's important to avoid temporal artifacts, the only good solution is to not drive your monitor at 144Hz—instead, go into your "Displays" control-panel and tell your operating system to actually drive it at 90Hz. If your hardware/drivers don't support this, then it's going to be a case of "pick your poison".

Poison A is to have the frame-update code run every 1/90 of a second on-the-dot whether the screen is physically ready or not. In this case you'll buy extra time to perform rendering (draw more/bigger stimuli) but, regardless of whether you needed that extra time or not, you'll inevitably get visual "tearing" artifacts as the screen is out of synch with VRAM.

Poison B is to dither the scheduling of the frames, so that updates are sometimes one physical frame apart (1/144 of a second) and sometimes two physical frames (2/144 of a second), averaging out to 1/90. In this case you won't get tearing, but animation will likely be jerky and irregular-looking. Also, in the shorter-duration frames, you're not getting any extra time for rendering, which may defeat the purpose.

Both of these are undesirable in nearly all the use-cases for which Shady was conceived, so Shady doesn't offer any pre-packaged solution for doing this. Below is a listing that accomplishes either solution, depending on whether you run it with --allowTearing or not. I set the default to --fps=40 , an arbitrary target less than 60 so that I could test it on my 60Hz setup; obviously you would want to run with --fps=90 .

Both solutions do involve a sleep() in Python (there would be no point in hacking something more-precise in the lower levels: the sleep is the least-awful of the problems with all of this). The difference between them is just w.SetSwapInterval(0) , the effect of which is to make the rendering code run as fast as it can without caring about physical screen timing at all (NB: this setting may actually be ignored on some graphics drivers, in which case you're stuck with Poison B).

import Shady, time

cmdline = Shady.WorldConstructorCommandLine()

allowTearing = cmdline.Option( 'allowTearing', False, type=bool )
fps = cmdline.Option( 'fps', 40, type=float )

cmdline.Help().Finalize()

w = Shady.World( **cmdline.opts )
Shady.TearingTest(w).z = 0
Shady.FrameIntervalGauge(w)

if allowTearing:
    w.SetSwapInterval( 0 )
else:
    w.SetSwapInterval( 1 )

w.awkwardFrameRate = fps  # change w.awkwardFrameRate on-the-fly if you want

@w.AnimationCallback
def Blah( self, t ):
    try:
        t0, n0, framesPerSecond = self._awkward
    except AttributeError:
        framesPerSecond = None
    if framesPerSecond != self.awkwardFrameRate:
        t0, n0, framesPerSecond = self._awkward = [ Shady.Timing.Seconds(), self.framesCompleted, self.awkwardFrameRate ]
        print( self._awkward )
    deadline = t0 + ( self.framesCompleted - n0 ) / framesPerSecond

    while Shady.Timing.Seconds() < deadline:
        time.sleep(0.001)

Shady.AutoFinish( w )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM