Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lower than expected FPS on some devices #1821

Open
keithclark opened this issue Jan 17, 2020 · 2 comments
Open

Lower than expected FPS on some devices #1821

keithclark opened this issue Jan 17, 2020 · 2 comments

Comments

@keithclark
Copy link
Contributor

While testing the editor on a Kindle Fire 8 I noticed that the player only seems to run very simple creations at a max of 30fps when using the Repeat every 1 frames block. The Kindle Fire is more than capable of running at 60fps for basic drawing operations.

Digging into the code I noticed that the rAF callback calculates the delta time between the current and previous frames to determine when to run the next update:

diff = timestamp - startTimestamp;
// Enough time passed since last frame, execute the code
if (diff >= dt) {
startTimestamp = timestamp;
callback();
}

It appears that this code isn't working correctly if rAF callbacks happen at inconsistent intervals. I've done some reading on FPS limiting and it seems that timing errors can be compensated for by changing this:

startTimestamp = timestamp;

to this:

startTimestamp = timestamp - (diff % dt);

In my case this works and bumps the frame rate back to 60fps. I also noticed an FPS increase on the PI3 kit. I was going to put a PR together with that change but I'd like your thoughts on this first.

In addition to (or instead of) the above, should there be a special case for when the "Repeat every n frames" interval is set to 1, as this should happen every rAF, regardless of frame deltas?

if (interval === 1) {
  this.frames[loopId] = requestAnimationFrame(func);
  return;
}

Any thoughts / ideas?

@pazdera
Copy link
Contributor

pazdera commented Feb 19, 2020

Hi Keith,

Thanks for raising this. We discussed this with the team, and the reason why we limit the FPS to 30 is to achieve relative consistency in rendering between different devices. When users share creations on our platform with the on every frame block, we're normalising the speed to 30 so the animations look the same when someone remixes it. It does come with a drawback of lower FPS.

Hope that makes sense.

@keithclark
Copy link
Contributor Author

That makes sense. But, if you're capping creations to 30FPS, I think you still have a bug. If I load this creation into Kano Code in Chrome and Firefox I get completely different frame rates:

  • Chrome: Rock-solid 60FPS
  • Firefox: 35-40FPS

My machine is capable or running that creation at 60FPS in both browsers, so 30FPS should be pretty stable. However neither browser seems to be running creations at that speed.

This is really noticeable when you create something on a PI Kit and later open it in a browser on a higher spec device - creations run at completely different speeds.

{
  "source": "<xml xmlns=\"http://www.w3.org/1999/xhtml\"><variables><variable type=\"\" id=\"%!A68BvlUj}jLF8@h_Lg\">ticks</variable><variable type=\"\" id=\"PG2z^~,|Q^A^XFf;/6RL\">done</variable></variables><block type=\"app_onStart\" id=\"default_app_onStart\" x=\"118\" y=\"91\"><field name=\"FLASH\"></field><statement name=\"CALLBACK\"><block type=\"variables_set\" id=\"Fr$GO`Lh{cW)vEJw_Slh\"><field name=\"VAR\" id=\"%!A68BvlUj}jLF8@h_Lg\" variabletype=\"\">ticks</field><value name=\"VALUE\"><block type=\"math_number\" id=\"ST]XY,c-JF`bI(Yx?!}e\"><field name=\"NUM\">0</field></block></value><next><block type=\"in_x_time\" id=\"9LnK@b](Avdjf7R%47x;\"><field name=\"UNIT\">seconds</field><value name=\"DELAY\"><shadow type=\"math_number\" id=\"ewzF=qFJ3nAPku=^7M7(\"><field name=\"NUM\">1</field></shadow></value><statement name=\"DO\"><block type=\"variables_set\" id=\"XS7[B;4j|ouQ8j^[B(TT\"><field name=\"VAR\" id=\"PG2z^~,|Q^A^XFf;/6RL\" variabletype=\"\">done</field><value name=\"VALUE\"><block type=\"logic_boolean\" id=\"*w}kz4o!VV%i],m;XVVY\"><field name=\"BOOL\">TRUE</field></block></value></block></statement></block></next></block></statement></block><block type=\"every_x_seconds\" id=\"9i+i8FNYI|+!BWjXlkNs\" x=\"117\" y=\"340\"><field name=\"UNIT\">frames</field><value name=\"INTERVAL\"><shadow type=\"math_number\" id=\"Iu/IU=L=R26KXQs_3i8b\"><field name=\"NUM\">1</field></shadow></value><statement name=\"DO\"><block type=\"controls_if\" id=\"z41lvg]I1b99Aiz/Mf)P\"><field name=\"CONFIG\">{\"elseIfs\":0,\"else\":false}</field><value name=\"IF0\"><block type=\"logic_negate\" id=\",@s@fISmfN/4-vcG^B;4\"><value name=\"BOOL\"><block type=\"variables_get\" id=\"~PT(T2|H%4[9rG/e@-kT\"><field name=\"VAR\" id=\"PG2z^~,|Q^A^XFf;/6RL\" variabletype=\"\">done</field></block></value></block></value><statement name=\"DO0\"><block type=\"sticker_moveTo\" id=\"Yg(75M%$w+NDFNBE}Fr]\"><value name=\"X\"><shadow type=\"math_number\" id=\"9r=%_jOQ/;;7C[]^R-Y_\"><field name=\"NUM\">0</field></shadow><block type=\"math_lerp\" id=\"Q=kkWsQW7F-n%`JOI5p^\"><value name=\"FROM\"><shadow type=\"math_number\" id=\"u0+q0$+s!3$J6NUQ{sqP\"><field name=\"NUM\">100</field></shadow></value><value name=\"TO\"><shadow type=\"math_number\" id=\"M*YVT2(c=K4R;XgW1O8F\"><field name=\"NUM\">700</field></shadow></value><value name=\"PERCENT\"><shadow type=\"math_number\" id=\"rLpGZfKp3creGK3FUS1=\"><field name=\"NUM\">50</field></shadow><block type=\"osc_value_get\" id=\"2-lD,-fa/;-o$|kL2[/(\"></block></value></block></value><value name=\"Y\"><shadow type=\"math_number\" id=\"znjN^(-t6VukrNk-Iur?\"><field name=\"NUM\">0</field></shadow></value><next><block type=\"text_value_set\" id=\")KuIM8UCp+{N-b_w|{k5\"><value name=\"VALUE\"><shadow type=\"text\" id=\"OP9}1cu]W/lVrU-wg}Ba\"><field name=\"TEXT\">Text</field></shadow><block type=\"variables_get\" id=\"O5)_l}=NF~,z(JP`=_lY\"><field name=\"VAR\" id=\"%!A68BvlUj}jLF8@h_Lg\" variabletype=\"\">ticks</field></block></value><next><block type=\"unary\" id=\"d3C8PMx0@~BYsvr(dwb1\"><field name=\"LEFT_HAND\" id=\"%!A68BvlUj}jLF8@h_Lg\" variabletype=\"\">ticks</field><field name=\"OPERATOR\">+=</field><value name=\"RIGHT_HAND\"><shadow type=\"math_number\" id=\"RJ]sE1?hZ-tR[X?YL/F1\"><field name=\"NUM\">1</field></shadow></value></block></next></block></next></block></statement></block></statement></block></xml>",
  "code": "var ticks, done;\n\n\napp.onStart(function() {\n  ticks = 0;\n  time.later(1, 'seconds', function () {\n    done = true;\n  });\n\n});\n\ntime.every(1, 'frames', function () {\n  if (!done) {\n    sticker.moveTo(math.lerp(100, 700, osc.value), 0);\n    text.value = ticks;\n    ticks += 1;\n  }\n});\n",
  "parts": [
    {
      "type": "sticker",
      "id": "sticker",
      "name": "Sticker"
    },
    {
      "type": "oscillator",
      "id": "osc",
      "name": "Osc"
    },
    {
      "type": "text",
      "id": "text",
      "name": "Text"
    }
  ],
  "profile": "default"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants