Jump to content

HELP - 60fps but bad stutter


Recommended Posts

Hi Everyone,

I'm working on a Guitar Hero / Rocksmith like game in Pixi.js: a song plays and some boxes scroll towards a cursor that lets a guitarist know how to play along. Website if anyone is interested: aimusiclessons.com.


I'm running into performance issues, specifically with stutter and after 1.5 weeks going through PIXI issues and HTML5 dev forums and trying a bunch of different approaches I'm completely lost with what to do next. The stutter really impacts UX and my sanity. Any help/guidance would be greatly appreciated. There's no crazy animations, filters, or massive amounts of sprites, so it should be running smooth even on a crappy device. For the experiments below I removed all the microphone monitoring and processing, it's just straight up PIXI and Howler (playing the mp3 file).

Example video of stutter issue (sorry for Justin Bieber - I'm sorry too, it's been my test song for 1.5 weeks).

I'm developing in Chrome (other browsers affected as well): dev tools says 60fps and no dropped frames, all render ticks are happening well within 16.6ms acceptable bounds. Mobile performance has stutter too, and lower fps ~40fps.

I've tried 2 different approaches to drawing boxes (boxes are variable width, so need to be scalable). There's max 15 boxes on screen at a time and max maybe 3000 boxes total in a 3.5min song.

  1. Each box is Pixi.Container containing a graphics object drawing roundedRect for the foreground, roundedRect for the background shadow, Pixi.Text for the number. I read there's a potentially a bunch of performance issues with Pixi.Graphics so I've also tried calling cacheAsBitmap on each box after assembling it when loading the stage to try to speed up rendering later on: seems to be a bit more stable in terms of stutter than my other attempts but still noticeably bad. I also don't love this approach because I need to change the box tint realtime and then need to disable cacheAsBitmap then re-enable which seems inefficient.
    ^ this is a frame that takes longer to render (some take 2ms, some 9ms like this one). With this approach, relatively low GPU usage (GPU tasks are each under 1ms), 60fps (we don't drop a frame), but stutter exists :( I think because variability in length of time to render frame. Don't appear to have bad GC calls.
  2. I found this post that Ivan responded to that suggests a sprite for the left of rounded rect, sprite for middle, and sprite for right of rounded rect. I created images in a sprite sheet for the left, middle (1px), and right of the boxes (sprite for each) and then setting .width on the middle sprite (tried both Sprite and TilingSprite) to have variable width boxes. Instead of using Pixi.Text, load image of text number from spritesheet. Stutter still exists. No bad GC calls.
    ^ with this approach all the frame renders seem to be much shorter (<2.5ms each). In other performance snapshots I saw longer GPU tasks in bad stutter sections (some up to 10ms long), but can't recreate that today.
    Edit: was able to recreate it this morning, here's the performance snapshot (see the bunch of grey peaks in the timeline corresponding with long GPU tasks):

    Here's Spector.js rendering out a frame

I've tried 2 different approaches to scrolling, culling:

  1. Putting all the boxes into one Pixi.Container. Changing the x position of the Container every tick to scroll all the boxes over. Culling algorithm runs every mod 15 frames that sets .visible/.renderable on off-screen boxes.
  2. Pooling: constructing a pool of 20 boxes on load and request/releasing them in culling algorithm when they would be on screen. Swap texture for text number I need. Set width (stretch) middle sprite to have the correct width box. Scroll by changing x position of each active box on stage directly: ~15 DisplayObject position updates per frame.

Other things I've tried:

  1. Seemingly every combination of PIXI.settings (antialiasing, resolution, GC_MODE, ROUND_PIXELS, etc.)
  2. https://github.com/pixijs/pixijs/issues/7771I do subclass PIXI containers and Sprites in my OOP code. I painstakingly changed that structure and it didn't help.
  3. Removing every object/widget on the screen except for the background guitar fretboard and the scrolling note boxes. Still stutter.
  4. Using pixi preloader (although I think loading BaseTexture from sprite atlas loads up the GPU anyways so redundant).
  5. POT spritesheet to enable MIPMAP. I ran into a bunch of issues with artifacts on the screen, but still didn't help stutter.
  6. Disabling all browser extensions running
  7. There's no transpiling happening with Babel, etc.

I just want this thing to run smoothly. It should be able to and that's why I'm frustrated (and length of time debugging this).

I created a CodePen with a minimal example that demonstrates the stutter: https://codepen.io/gburlet/pen/QWqxxLE. This uses @ivan.popelyshev's idea of rendering variable length boxes with 3 sprites and culls using a Sprite pool. If you sit and watch the movement, sometimes it's smooth and then stutters here and there, and sometimes gets into bad sections of stutter then recovers, at least on my macbook, mac pro, iPad, iPhone (all > 2017 devices). On my beefy gaming computer with nvidia card seems to run OK.

Any suggestions, guidance, advice, help? Thanks!

Link to comment
Share on other sites

  • gburlet changed the title to HELP - 60fps but bad stutter

What operating system are you running on? I had a similar issue with linux when using certain compositors where GPU & CPU times were all well within frame limits and still had occassional stutter.

Also is it possible to test the game onthe website without registering?

Link to comment
Share on other sites

Checked the game with chrome on windows. Couldnt get any noticable stutter except when running with 3 dpr. Also the profile & spector looked good. One thing that might cause the gpu spike you see in the new image is if that one used the cacheAsBitmap option as it might end up generating lots of textures due to caching. 

I'll leave the codepen example running for night to check if it might be something memory related and doesn't appear immediatly on windows.

Also can you try these settings on the code pen instead of current pixi app creation:

const canvas = document.getElementById("app");
const ctx = canvas.getContext("webgl2",{
  powerPreference: 'high-performance'

let app = new Application({
    resizeTo: document.getElementById("app-container"),
    view: document.getElementById("app"),
    backgroundAlpha: 0,
    autoDensity: true,
    autoStart: false,
    resolution: window.devicePixelRatio,

And a combination of those with alpha on/off, desync on/off & alias on/off.

Also check if limiting resolution to 1 or 2 changes stutter amount.

Edited by Exca
Added resolution check.
Link to comment
Share on other sites

@ExcaThanks for the other options to try. I tried every combination and apart from making the UI look kind of janky (especially when AA is set to false) nothing changed the stutter in any meaningful way. The desynchronized option looked promising after reading more about it and something I hadn't tried before.

Here's what the performance looks like on my 2017 macbook pro, up-to-date Chrome, and all the performance enhancements I can think of from the video game dev world (pooling, culling, etc.). I'm sad that I'm on week 4 of trying to get this thing to be smooth and felt like I've made no progress :(



Link to comment
Share on other sites

Interestingly the pixie runner example is smooth on all devices. Frames render in ~1.5ms while on the same device my pixie app renders each frame in ~1.6-2ms which is well under 16ms for 60fps. Hmmm. The main difference between my code and something like pixie runner is obviously there's much more of it, and it's heavily object oriented: each thing on the screen is it's own class, like a NoteBox is a class that has a PIXI.Container of sprites that make up the box that will move horizontally across the screen. Each box is added to a class that extends a PIXI.Container. Maybe it's just all too much for Javascript and the code architecture just needs to be one god file? It would be suck to have to remove such clean code structure for performance, but ultimately performance wins.

Another thing that's potentially different is stretching sprites, like for example the middle of each box can be variable width (depending on the length of it) so the underlying BaseTexture on the sprite sheet is 1px wide and then I call .width = x on the sprite to stretch that texture out. Maybe that puts unnecessary strain on the rendering and GPU?

Does anyone have examples of PIXI games that are object oriented? I found an old McDonalds runner game that was PIXI v1 (super old) through the PIXI gallery and it had a bunch of classes and ran fine on my devices that exhibit stutter with my app, so maybe that's not the issue either. Any other ideas why I could be experiencing poor performance?

BTW @Exca I really appreciate your help and brainstorming. Thanks!

Edited by gburlet
Link to comment
Share on other sites

I have no idea how OO programming could create stutter unless it would generate lots of memory reserving/freeing but that would cause much steeper sawtooth in profiler. Also setting width is basically same as if you would calculate scale x value. That shouldnt affect rendering unless in cases where pixel fill rate starts to be affected. Didnt see such things in your case.

I usually tend to do OO based approaches with pixi. Here's some game jam games you can test if you want, though most of those are pixi v4. Dont have any commercial stuff available publicly online.


Link to comment
Share on other sites

  • 1 month later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...