• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!
  • Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

(SOLVED) FPS dropping below room speed while real fps is still triple-digits

Popfan

Member
EDIT: So at this point I'm reasonably certain that this might've been a hardware issue all along. Two days ago, my computer stopped recognizing my graphics card, which I was suspecting had been dying for a while now, so I plugged my display into my motherboard's DVI port instead, and ever since I did that, I haven't had any slowdown whatsoever. As such, I'm marking this as solved. Apologies for the anticlimactic resolution.

So this is an issue that's been bugging me for some time now and I can't seem to find much in the way of people with similar issues. The one thread I did find only mentioned tweaking the sleep margin, which isn't making much of a difference for me.

My problem is as it says on the tin: At certain points while running the game, it slows down visibly, sometimes as much as 30fps (my room speed is set to 60 throughout), but when I look at the the debug overlay, not only is the framerate there in the triple digits, there doesn't even seem to be any particularly strong overhead going on. What makes it even more vexing is that, while it generally happens in the same places, it doesn't always happen and sometimes the framerate is the same buttery-smooth 60fps that I expect it to be. I've tried looking into it with the IDE's debugger, too, but again, I couldn't find anything that could make the game choke like that.

The only thing I've been able to figure out so far is that pausing the game while such slowdown is going on makes the framerate recover again, at least until I unpause. Given that pausing in my case essentially means "halt step event code execution of just about all instances except for a select few", that makes it sound like it should be an issue with my code, but again: real fps is way higher than the room speed and the framerate dips don't always happen.

Anyone know where to even begin troubleshooting this?
 
Last edited:

Mert

Member
fps_real or fps does not actually reflect the final state of your game. Most of the issues I've had like this happens when I overuse GPU resources.
I'd check for gpu calls and vram usage
 

Popfan

Member
Check where/how exactly? If it's with GMS2's debugger, I still barely know how to use it, so if you could walk me through what I'd need to do to check with it, I'd be grateful.

What I've been checking was my GPU resources via task manager, but the only really noteworthy thing was dedicated VRAM usage getting nearly maxed out (granted, I only have about 1GB total and it's sitting at 60% usage without the game open). On the other hand, the slowdowns refused to be as prevalent now that I was actively trying to benchmark for them, so...

As an aside, I also recall that GMS1.4 builds of my game seemed to run a lot better for some reason.
 
First and foremost, do the excellent Debugger tutorial by @Nocturne.
Debugger is an ESSENTIAL tool, much more so than you imagine. It can tell you everything there is to know about your game, and then some.
The Debugger (yoyogames.com)
If your VRAM is maxed out, there's most likely something very unoptimized going on in your draw calls, that's often easy enough to get some extra horsepower there without too much trouble, so this is good.
Without code, tho, you're on your own with the Debugger :)
 

Popfan

Member
I looked at the tutorial, and -- with plenty of trial and error on my end -- got the debugger to show me the textures and surfaces in use. Oddly enough, some of the surfaces listed were completely empty. Is that at all normal?

What I'm also wondering whether or not it's normal is that it listed every single texture the projects has, even though I know for a fact I'm flushing and prefetching them as needed. That doesn't mean GMS loads every single texture into VRAM regardless, does it?

If we're talking code, the only common thread I could think of would be what I'm doing with the application surface. For context: my game has a native resolution of 1280x960, which can be downscaled to 960x720 or 640x480. What I'm doing is perhaps a bit unnecessary and convoluted, but I've got another surface that is scaled to the currently set window resolution and that the application surface is then drawn to. This essentially retains the resolution even in fullscreen on a display that's obviously much bigger than the selected resolution.

So this is what I have in the draw event:
GML:
//Draw application surface to game surface
if (!surface_exists(global.game_surf)) window_resize();
surface_set_target(global.game_surf);
gpu_set_blendenable(false);
gpu_set_colorwriteenable(true,true,true,false);
var sw = surface_get_width(global.game_surf) / 1280,
    sh = surface_get_height(global.game_surf) / 960;
draw_surface_ext(application_surface,0,0,sw,sh,0,c_white,1);
gpu_set_blendenable(true);
gpu_set_colorwriteenable(true,true,true,true);
surface_reset_target();
window_resize() just resizes global.game_surf to the required size if it exists, or creates it at the required size if it doesn't.

And then I've also got a draw GUI event in the same object:
GML:
gpu_set_blendenable(false);
if (!window_get_fullscreen()) { //windowed mode
    display_set_gui_maximise();
    draw_surface(global.game_surf,0,0);
} else { //I do most of my testing in windowed, so the below can probably be disregarded for now
    var sw = surface_get_width(global.game_surf),
        sh = surface_get_height(global.game_surf),
        ww = display_get_width(),
        wh = display_get_height(),
        sx, sy;
        
    if (global.stretch) { //whether or not to distort the aspect ratio in fullscreen
        display_set_gui_maximise();
        sx = ww / sw;
        if (ww > wh) sy = wh / sh;
        else sy = sx * .75;
    } else {
        if (ww > wh) {
            sy = wh / sh;
            sx = sy;
        } else {
            sx = ww / sw;
            sy = sx;
        }
        display_set_gui_maximise(1,1,(ww - (sw * sx)) / 2,(wh - (sh * sy)) / 2);
        if (global.fullscreen && ww > wh) {
            //This just draws some graphics to fill out the pillarboxing
            var frame_s = wh / 1080;
            draw_sprite_part_ext(sp_frame,0,0,0,240,1080,-240 * frame_s,0,frame_s,frame_s,c_white,1);
            draw_sprite_part_ext(sp_frame,0,240,0,240,1080,1440 * frame_s,0,frame_s,frame_s,c_white,1);
        }
    }
    draw_surface_ext(global.game_surf,0,0,sx,sy,0,c_white,1);
}
gpu_set_blendenable(true);
Honestly, though, I have no idea if the above code is even relevant at all...
 
I looked at the tutorial, and -- with plenty of trial and error on my end -- got the debugger to show me the textures and surfaces in use. Oddly enough, some of the surfaces listed were completely empty. Is that at all normal?

What I'm also wondering whether or not it's normal is that it listed every single texture the projects has, even though I know for a fact I'm flushing and prefetching them as needed. That doesn't mean GMS loads every single texture into VRAM regardless, does it?
Really glad you got into the debugger!
As for flushing the textures, it's supposed to flush them from video memory. They will be automatically loaded if anything on that texture sheet needs to be rendered, tho, meaning the whole texture page could be loaded just to use a pixel in some other texture page. From what you're saying, tho, it sounds like you got things well organized in your texture pages, but I'd double-check that nonetheless, sometime we add a sprite or something later in developement and forget to assign it to a specific page (happens to me all the time, at least, lol).

When you start profiling, you can also see the time it takes to execute stuff, is anything obviously weird, when you look at it? Like someting getting called multiuple times every step for no reason, or something with a very high Step% ?
Refer to the last part of the tutorial if you need a refresher!
 

c023-DeV

Member
... What makes it even more vexing is that, while it generally happens in the same places, it doesn't always happen...
That does sound like Images loading from a new texture group, that can make the game stutter sometimes. So if you restart the same room and the stutters don't happen then it might be that (because after a room restart the textures are still loaded if not flushed). If you use texture flush at the room start (for testing) and then they always happen at the same locations then I'd be pretty sure it's texture loading.
To avoid that happening you can draw one sprite from each texture group once that you are using at the start of your room (can draw them off screen or during a fade-in so they don't get seen). That would make sure that all texture groups are loaded.

As with the sleep margin, I used to have that issue with my older notebooks CPUs power saving and it does feel like the effect that you describe.
If you can then maybe try an run your project on different (also older/weaker) machines for reference.

Other than that the debugger is the way to go to find potential fps killers.
 

Ricardo

Member
Have your tried your project with the latest Beta? If I remember correctly, they got a few bugs fixed related to what you are describing.
 

Popfan

Member
As for flushing the textures, it's supposed to flush them from video memory. They will be automatically loaded if anything on that texture sheet needs to be rendered, tho, meaning the whole texture page could be loaded just to use a pixel in some other texture page. From what you're saying, tho, it sounds like you got things well organized in your texture pages, but I'd double-check that nonetheless, sometime we add a sprite or something later in developement and forget to assign it to a specific page (happens to me all the time, at least, lol).
So what I'm doing is initializing several texture group arrays (usually one for each room). I then have a function that, depending on the argument given, loads one of those arrays with sprite_prefetch_multi(). Texture memory management is primarily handled by the object I use to move between rooms (in order to have a transition effect): It does, within the span of a step, in the following order: flush all textures, load the necessary textures via the aforementioned function, then proceeds to the next room. I've also made sure I don't have any stragglers such as sprites I forgot to account for, so I don't think this could be the issue at all.

That does sound like Images loading from a new texture group, that can make the game stutter sometimes. So if you restart the same room and the stutters don't happen then it might be that (because after a room restart the textures are still loaded if not flushed). If you use texture flush at the room start (for testing) and then they always happen at the same locations then I'd be pretty sure it's texture loading.
To avoid that happening you can draw one sprite from each texture group once that you are using at the start of your room (can draw them off screen or during a fade-in so they don't get seen). That would make sure that all texture groups are loaded.
See above. Also, you shouldn't need to draw the sprites anywhere if you're using sprite_prefetch(), as that loads the sprite's corresponding texture page into memory, too. Supposedly, anyway.

When you start profiling, you can also see the time it takes to execute stuff, is anything obviously weird, when you look at it? Like someting getting called multiuple times every step for no reason, or something with a very high Step% ?
No, and that's the weird thing. When those slowdowns happen, profiling yields nothing out of the ordinary.

Have your tried your project with the latest Beta? If I remember correctly, they got a few bugs fixed related to what you are describing.
I hadn't, but I looked through the release notes for the latest beta build and the closest I could find was this:
  • In-Game: Fixed the scheduler/vsync changes in 2.3.3 which caused low FPS values for some users of high-refresh monitors
  • Note that we did find an issue could be replicated on regular 60hz monitors also, so all users might have been affected regardless of monitor model
So I tried it, and... I think the issue might still be persisting. Oddly enough, though, when I experienced the slowdown, it seemed to go away after the window lost and regained focus, so perhaps it's surface-related, after all?
 

Popfan

Member
Bit of a necropost, but at this point I'm reasonably certain that this might've been a hardware issue all along. Two days ago, my computer stopped recognizing my graphics card, which I was suspecting had been dying for a while now, so I plugged my display into my motherboard's DVI port instead, and ever since I did that, I haven't had any slowdown whatsoever. As such, I'm marking this as solved. Apologies for the anticlimactic resolution.
 
Top