Inherit frame rate from display

edited November 2017 in Android Mode

So I've optimized my sketch so every thing runs on the same speed independent from the frame rate so now someone with 30 fps can play at the same speed as someone with 90 fps but it looks smoother for the 90 fps user

But I wondered, the default refresh rate is 60, but I want people with a higher refresh rate to be able to use the app their frame rate limit. (I know its quite rare to find a phone with a 60+ fresh rate but they are out there), so how would I go about that, if I just set the frame rate to 240 and then run it on a 30 fps screen it will just waste computing power trying to get the fps higher than i can actually display it right?

In short, how do I detect the frame-rate of a device and then run processing at that frame rate

Answers

  • I believe that you can simply set it to the higher frameRate.

    Specifies the number of frames to be displayed every second. For example, the function call frameRate(30) will attempt to refresh 30 times a second. If the processor is not fast enough to maintain the specified rate, the frame rate will not be achieved. Setting the frame rate within setup() is recommended. The default rate is 60 frames per second. -- https://processing.org/reference/frameRate_.html

    Keep in mind that the result also depends on the Hz of your screen refresh rate. My MacBook Pro laptop screen is 60Hz, which means that even if your sketch could render 120 frames a second, I wouldn't actually see them on the screen.

    This is true even for frameRate testing. For example, this sketch shows me that my laptop is able to render 110 frames per second in memory -- but that doesn't mean the screen can display that many frames!

    int lastFrame;
    int lastMillis;
    int thisFrame;
    int avgFrame;
    void setup() {
      lastMillis = millis();
      frameRate(110);
    }
    void draw() {
      background(0);
      thisFrame = 1000/(1+millis()-lastMillis);
      text("millis:   " + millis() + "\n" +
           "fcount: " + frameCount + "\n" +
           "fps:      " + thisFrame + "\n" +
           "avg:      " + frameCount/(millis()/(float)1000) + "\n",
           10, 20);
      lastMillis = millis();
    }
    
  • @jeremydouglass Thanks for your response! I understand that your screen has a frame limit, thats why I was concerend about just setting the frame rate to 120 fps since I would just be wasting cpu trying to reach 120fps while the screen can only display 60 fps, but your suggesting to just set the framerate high?

  • edited November 2017 Answer ✓

    Re: if Processing can know what the device refresh rate is, I'm actually not sure! For example, on my machine this returns "Unknown rate / refreshRate: 0":

    import java.awt.DisplayMode;
    import java.awt.GraphicsDevice;
    import java.awt.GraphicsEnvironment;
    
    void setup(){}
    void draw(){
      background(0);
      if(millis()>3000){
        checkScreen();
        exit();
      }
    }
    
    void checkScreen(){
      GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
      GraphicsDevice[] gs = ge.getScreenDevices();
      for (int i = 0; i < gs.length; i++) {
        DisplayMode dm = gs[i].getDisplayMode();
        int refreshRate = dm.getRefreshRate();
        if (refreshRate == DisplayMode.REFRESH_RATE_UNKNOWN) {
          println("Unknown rate");
        }
        int bitDepth = dm.getBitDepth();
        int numColors = (int) Math.pow(2, bitDepth);
        println("refeshRate: " + refreshRate);
        println("bitDepth  : " + bitDepth);
        println("numColors : " + numColors);
      }
    }
    
  • @jeremydouglass weird, for me it works and returns the correct refresh rate. I'll just try to get the screen rate and if it returns unknown / 0 it will just go to 60fps, otherwise it will use the screens actual refresh rate :)

  • Glad it works for you -- seems like it might be hardware-specific. Does it work if you call it in setup(), or do you need to call it in draw()?

  • @jeremydouglass It works fine in setup(), I'll be putting this in my app and releasing it. it will return the result to my server. So I'll be able to report back with some fun stats on how many android devices it actually works.

  • EDIT: Turns out the code doesnt work on android mode :(

    This is the code I'm using:

    String getFrameRate() {
      GraphicsDevice[] screens = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
    
      String refreshRate;
      refreshRate = str(screens[0].getDisplayMode().getRefreshRate());
      if (screens[0].getDisplayMode().getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN) refreshRate = "UNKNOWN";
      if (screens.length > 0) refreshRate = "MULTIPLE";
      return refreshRate;  
    }
    

    and this is the error:

    FATAL EXCEPTION: Animation Thread
    Process: processing.test.moderately_interesting_java, PID: 9083
    java.lang.NoClassDefFoundError: Failed resolution of: Ljava/awt/GraphicsEnvironment;
        at processing.test.moderately_interesting_java.Moderately_interesting_java.getFrameRate(Moderately_interesting_java.java:368)
        at processing.test.moderately_interesting_java.Moderately_interesting_java.draw(Moderately_interesting_java.java:40)
        at processing.core.PApplet.handleDraw(Unknown Source:147)
        at processing.core.PSurfaceNone.callDraw(Unknown Source:19)
        at processing.core.PSurfaceNone$AnimationThread.run(Unknown Source:55)
    Caused by: java.lang.ClassNotFoundException: Didn't find class "java.awt.GraphicsEnvironment" on path: DexPathList[[zip file "/data/app/processing.test.moderately_interesting_java-MTNEnRLBXkXycmezoFr3XQ==/base.apk"],nativeLibraryDirectories=[/data/app/processing.test.moderately_interesting_java-MTNEnRLBXkXycmezoFr3XQ==/lib/x86, /system/lib, /system/vendor/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:93)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        ... 5 more
    
  • Got it. So the java.awt.GraphicsEnvironment library / class wasn't in your path.

    Not an Android developer, so I'm not sure where to go from there. Maybe move this question into the Android forum channel?

  • edited November 2017

    @scholtz===

    As far as i know there is no api way to get the max frameRate for a device with android: with .BUILD api you can only know the physical specs of your phone + OS; you can get the max fps only with shell adb: yet it tells nothing about the real actual fps of your app, which you can get only by code: time (average) between 2 draw() but which can change from a moment to another one according to the needs of the android system and phone state...

    Your error is simple to explain: android does not use javaAWT and has its own Android.Graphics lib.

  • @akeaton Well thats al I need, I wanna know the max fps the device can display, so could I use shell adb? I dont need to know the actual fps I just want to set the frameRate to the devices actual frame rate

  • edited November 2017

    @akenaton I think the question is whether you can retrieve information on the standard Hz of the display -- so not how many frames Processing can render using CPU per second (~136), but how many actually screen-refreshes the device is performing per second (60).

    This assumes sketch will be running faster than the screen and is trying to save CPU / battery by not setting frameRate too high.

    Or was your answer above that this isn't possible?

  • Answer ✓

    @jeremydouglass, @schotsl===

    sorry, i misunderstood; if you want only to get the "standard" Hz of the display you can use the display android API && its getRefreshRate() function which returns it (float) per second. But there is not any "set" corresponding function,for "lowering" this refresh rate, though it seems that it could be possible (PSR does that). Anyway, nowadays, 60hz is the average refresh rate for phones, for battery draining reasons.

    more details here: https://developer.android.com/reference/android/view/Display.html#getRefreshRate()

  • edited November 2017

    @akenaton Thats perfect for what I want, I can get the displays frame rate trough getRefreshRate(); and then set that frame rate as the default with the frameRate(); function.

Sign In or Register to comment.