gburlet Posted January 5, 2022 Share Posted January 5, 2022 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). app_stutter_example.mp4 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. 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. 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: 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. 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: Seemingly every combination of PIXI.settings (antialiasing, resolution, GC_MODE, ROUND_PIXELS, etc.) https://github.com/pixijs/pixijs/issues/7771: I do subclass PIXI containers and Sprites in my OOP code. I painstakingly changed that structure and it didn't help. Removing every object/widget on the screen except for the background guitar fretboard and the scrolling note boxes. Still stutter. Using pixi preloader (although I think loading BaseTexture from sprite atlas loads up the GPU anyways so redundant). POT spritesheet to enable MIPMAP. I ran into a bunch of issues with artifacts on the screen, but still didn't help stutter. Disabling all browser extensions running 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! Quote Link to comment Share on other sites More sharing options...
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.