Randomly uneven framerate - & possible solutions?

BlitzMax Forums/BlitzMax Programming/Randomly uneven framerate - & possible solutions?

Sokurah(Posted 2014) [#1]
I'm having an annoying problem. I'm working on a Windows game (Mac comes later) which runs at a fixed 1024x768 resolution and I'm getting a lot of framerate choppiness and shearing. The backgrounds in this game are fullscreen PNG files.

Like I said - I'm getting a lot of shearing and choppy movement...but not always. Sometimes - without recompiling - I just exit the game and enter it again and the problem is gone. Or the other way around...and I just can't see what's causing it.

I've tried on two different computers and with both DirectX and OpenGL, but the results are the same. The same is experienced by the artist. I can only speak for myself, but both of my computers are pretty capable (I can run most new commercial games at 1920x1080) and my graphics drivers are up to date too.


Here's two ideas I'd like your opinions on;

1).
Most of my PNG images are 256 colors, but some are 16mil.
Could this mix have anything to do with it and would it make any difference to keep them all the same amount of colors?

2).
My backgrounds are actually drawn at half resolution and scaled up x2 in an artpackage before incbin'ning then into the game.
So, my second question is: Do you think it would help if I stored the background images at that half res - 512*384 - instead of twice that - and scale them up ingame using the SETSCALE command instead?


Brucey(Posted 2014) [#2]
If you Flip with the vertical blank (Flip, or Flip -1, or perhaps Flip 1), you shouldn't see any shearing.

Don't use DrawPixmap - which I hope you are not, as it is generally rubbish with most drivers.


Derron(Posted 2014) [#3]
Scaling the images saves on VRAM as you then let your GPU scale the images.

Prescaling in the artpackage allows to use more advanced scaling mechanisms (lanczaros etc.).

Best is to have the real artwork done in a way bigger res so you only scale DOWN.


@tearing
check if you set the graphics driver to ignore screen refresh rates ... and if you use flip -1/0/1


bye
Ron


GfK(Posted 2014) [#4]
You haven't said what your PC spec is, beyond "pretty capable", which is very much open to interpretation. I used to do mobile tech support and asked someone how old their PC was - their reply; "oh, it's pretty new, got it about 6 or 7 years ago". New to them. To me, obsolete.

Anyway, from what you've said, and without seeing any code, it sounds to me like your timing code (you have timing code, right?) is screwed somewhere. Your game is rendering as fast as it will go, then some background task kicks off on your PC and all of a sudden your game can't maintain the framerate for a split second. It will be massively noticeable.


Sokurah(Posted 2014) [#5]
Brucey,
If I use Flip 1 or -1 it's the same. Using Flip 0 makes it go blindingly (and unusably) fast (about 4600 fps).
And I don't use Pixmaps.
The performance I'm describing is in windowed mode btw. It's completely slow and useless when running fullscreen. Very odd, never had that problem before.


Derron,
The artwork is made at half res and is designed to be scaled up x2 without any filters - just a simple pixel-resize. I like it that way. Very retro-like. ;-)
I'm just using the "normal" Flip (without a number after it), but as you can read above it doesn't make any difference.
The graphics driver is not set to ignore screen refresh rates. Well, checking the settings it says "Use 3D-software settings", but there are no settings in that section for BM games.


GfK,
My specs are Core i7, 3.40GHz, 8GB RAM, GeForce GTX 560.
Certainly enough to run a BlitzMax game. ;-)


So as the game will happily go 4600 fps it's not because it's rendering as fast as it will go.
I'm guessing the Flip (which is basically a Flip 1, right?) just syncs it with the screen refresh rate.

But as you can guess - there is no timing code. I've never had a use for it before. But surely it should be able to keep things smooth when syncing with the screens refresh rate?


Brucey(Posted 2014) [#6]
Could be a memory leak.

Could be that the garbage collector is getting really busy at times clearing up a lot of objects.

Difficult to say without knowing more about what you are doing internally.


zoqfotpik(Posted 2014) [#7]
Just throwing it out there: for some reason both Blitz and Monkey seem to be very sensitive to other things running in the background. Often even Google Chrome will interfere with framerate and it does so in the form of microhitches. This has been true for me across two radically different machines.


*(Posted 2014) [#8]
Do you have a Delay( 1 ) in the main loop or in CPU intensive areas (where time taken is longer than 1 second), if not windows could be querying your app as it could be maxing out the cpu.

I always put it at the bottom of the main loop this frees the cpu cycles and can make a choppy game smooth :)


Matty(Posted 2014) [#9]
Hang on...your statement that flip 0 (which I imagine is without vsync) causes it to go uncontrollably fast suggests you aren't using any timing mechanism at all but rather simply letting it run as fast as the system will allow you....that is a problem right there.


GfK(Posted 2014) [#10]
You said you aren't using timing code. your graphics are rendering at 4600 fps - fine, but your logic is also running at 4600 fps. When your PC does something else in the background then your code can no longer execute 4600 times per second, and that's why you're having problems.

implement timing code to cap your frame rate to 60fps, and you can 99.9% guarantee the game will run a lot better for it.

there are plenty of timing examples in the code archives.


Derron(Posted 2014) [#11]
Sometimes it also matters if you are running debug or release builds.

My game is limited to 60fps and 30 updates per second (fixed rate logic + interpolation or extrapolation if needed) ... but when doing debug builds I am not able to have 60fps but it runs slower, 45fps. As in release mode and unlimited fps I have about 200 I think that debug in some cases is not just a bit but way slower. Maybe it collects garbage differently (does more in that case) ... so this will increase "hickup time" even more.


bye
Ron


Brucey(Posted 2014) [#12]
In debug mode there are *lots* of extra things going on :
* Each local block modifies the debug stack - that's two calls at least... one coming in, one going out.
* Each statement produces an extra function call.

It gets busy in debug mode :-)


zoqfotpik(Posted 2014) [#13]
Sometimes it also matters if you are running debug or release builds.

Oh, a LITTLE. That's the first thing to check. Knowing that, I've probably spent a week total trying to figure out why things were running blazingly slow.


Sokurah(Posted 2014) [#14]
You said you aren't using timing code. your graphics are rendering at 4600 fps - fine, but your logic is also running at 4600 fps. When your PC does something else in the background then your code can no longer execute 4600 times per second, and that's why you're having problems.

implement timing code to cap your frame rate to 60fps, and you can 99.9% guarantee the game will run a lot better for it.


Surely the logic isn't running at 4600 fps. It should be limited to the refresh of the screen, which in my case means it's running at (around) 60 fps.

I've never actually used timing code in any of my games - just designed them to run perfectly at 60 fps, but I supposed it would then run 25% faster for someone with a monitor refresh rate of 75 fps?
...not that anyone has ever complained. :-D


Sometimes it also matters if you are running debug or release builds.


I've made many games - most of them in BlitzMax so I've gotten over the "accidentally compiling in debug mode" period a LONG time ago. That's not it. :-D

It's just that choppy movement has never been an issue before and about 10 of my games are running in 1024x768 without any problems. But then again - none of them has involved as big images/sprites as this one so I was thinking it could somehow be related to that.


Still, perhaps this would be a good time to look into timing code - getting that to work properly would at least eliminate that as a potential problem.
...Can anyone direct me to an easy guide/example they know works? ;-)


Derron(Posted 2014) [#15]
You will find enough samples when searching "delta timing" or "fixed rate logic".


Maybe you should provide a simple example with slowdown (you can dynamically create images ... so no need to pass assets around for us).


@75hz
Yepp, it would run faster for them - if you just do a "move + 1" each "update".

deltaTime would then do "move + 1 * portionOfSecondGoneSinceLastUpdate"


bye
Ron


GfK(Posted 2014) [#16]
Surely the logic isn't running at 4600 fps. It should be limited to the refresh of the screen, which in my case means it's running at (around) 60 fps.
It's just an exaggerated example.

I've never actually used timing code in any of my games - just designed them to run perfectly at 60 fps, but I supposed it would then run 25% faster for someone with a monitor refresh rate of 75 fps?
...not that anyone has ever complained. :-D


Your game might well be running at your monitor refresh rate of 60Hz but on many GPUs it's possible to force override vSync to Off. In that case, your code will run as fast as the hardware is capable of, be it 60Hz, or 6,000Hz. Your game would then run unplayably fast as a result, because you aren't using any form of timing beyond what your own hardware is set to.

By implementing timing code and detaching logic from rendering, your game logic will always run at the same speed, and rendering will take place as and when there's time to do it.


skidracer(Posted 2014) [#17]
Or you BIOS may be incorrectly configured and the video IRQ is shared with something else or your plug'n play is simply disabled.


Sokurah(Posted 2014) [#18]
Derron: "Maybe you should provide a simple example with slowdown (you can dynamically create images ... so no need to pass assets around for us)."


Okay, I made a stripped down demo that has about 6 screens where you can see the problem in action. The demo is a mere 1.7MB in size.

https://dl.dropboxusercontent.com/u/2697142/DwWhoDemo.rar

Here's a picture so you know what you're downloading.



All the screens here are among the first I added so they're still at full res - 1024x566 (plus the bottom panel added afterwards). The other 15 screens added (which are not included in this demo) are at half that (512x283) and scaled up...but the problem is still there...although it may be less prominent (but it's pretty random).


Derron(Posted 2014) [#19]
With demo I meant:

- simple sourcecode
- basic assets

Your exe might have a "delay 1000" in it ... we wouldn't see that.

So if you are able to strip down the whole thing into some sourcecode + media: we could more likely see what the problem might be.

Maybe it is some eventhandling, some timers, some ...


bye
Ron


Pingus(Posted 2014) [#20]
Seems working fine here... (60 fps)


Sokurah(Posted 2014) [#21]
With demo I meant:

- simple sourcecode
- basic assets


Oh.

Well, I've stripped the source code completely down to the bare essentials...and the problem is still there.

Please read the 'readme-first.txt' file before you ask any questions, I may have adressed them there.

https://dl.dropboxusercontent.com/u/2697142/DrDemo.zip

This demo is about 1 MB in size and contains source code, assets and an executable.

I hope there are some among you that can help me with my framerate problem.


Derron(Posted 2014) [#22]
First of all:

SuperStrict
?Win32
	Import bah.fmod
?Not Win32
	Import "incl\soundwrapper.bmx"
?

'Dirext X
Framework brl.D3D7Max2D


Ahh... so when not running "windows", it tries to include a file in "bla\". Also the Framework is limiting to windows already.

Use "/" if possible, on Linux/Mac this is the default path divider.

"incl/soundrwapper.bmx":
cannot compile it ...maybe using a framework makes it hmm less compatible (you should really use "superstrict" and import things in individually imported files).

Game needs fmod-module to work.


Code like this:
	If Examining = 0 Then

		If Idle = 0 Then
			If Direction = 0 Then CurrentFrame = Frame + (Direction * 10)	' Right
			If Direction = 1 Then CurrentFrame = 16 - Frame
			DrawImage PlayerGFX, Xpos, Ypos, CurrentFrame
		Else
			If Direction = 0 Then CurrentFrame = 7	' Right
			If Direction = 1 Then CurrentFrame = 19	' Left
			DrawImage PlayerGFX, Xpos, Ypos, CurrentFrame
		End If

	Else
	
		CurrentFrame = 26 + (Examining / 8 Mod 4)
		DrawImage PlayerGFX, Xpos, Ypos, CurrentFrame
		If Examining > 0 Then Examining = Examining - 1
	
	EndIf


Why not just:

	If Examining = 0 Then
		If Idle = 0 Then
			If Direction = 0 Then CurrentFrame = Frame + (Direction * 10)	' Right
			If Direction = 1 Then CurrentFrame = 16 - Frame
		Else
			If Direction = 0 Then CurrentFrame = 7	' Right
			If Direction = 1 Then CurrentFrame = 19	' Left
		End If
	Else
		CurrentFrame = 26 + (Examining / 8 Mod 4)
	EndIf

	DrawImage PlayerGFX, Xpos, Ypos, CurrentFrame
	If Examining > 0 Then Examining = 1 - Examining


Also pay attention to "Examining = Examining - 1" ... if you want an alternation between 0 and 1 you better write "examining = 1 - examining", else a starting value "examining = 0" will lead to "-1" (which then in the next case will lead to "= 1 - -1 = 2"). No true "boolean" values (but of course still working).

That "drawing" could be done at the end of the function as all other things just calculate the frames. - but that is not the source of the problem.


The problem is: you move at constant "pixel-distances" regardless of the time gone since the last frame.

You cannot guarantee to have each frame taking exactly 1.0seconds / amountOfFramesPerSecond. So if one takes 16ms, the other takes 18, nother one 15.7 ...

But each of these frames you let your character move by X pixels. So this makes the whole thing "jitterish".


That is why people use "deltatiming".
You wont any longer define "pixels per frame" but "pixels per second". Now for each frame you check the milliseconds gone since last frame... and this is your "deltatime". If your last frame was 17ms ago, your Figure moves then by 0.017 * pixelsPerSecond.

Of course it also might lead to some kind of "jittering" (because of rounding errors).



Another tip is to reorganize a bit of your code.

"Type Snow" - it could contain "addSnow" and other functions too.


Other thingies:
#IdleWorkingFrameData
DefData 0, 0, 0, 1, 2, 3, 3, 4, 4, 3, 3, 4, 4, 5, 6, 7, 8, 9, 0, 0
Global WorkingFrameSequence:Int[21]
RestoreData IdleWorkingFrameData
For a = 0 To 19
	ReadData b
	WorkingFrameSequence[a] = b
Next


Why so complicated?

Global WorkingFrameSequence:Int[] = [0, 0, 0, 1, 2, 3, 3, 4, 4, 3, 3, 4, 4, 5, 6, 7, 8, 9, 0, 0]



Also of interest:
Function ShowItems()
	For Local item:items = EachIn items_list
		f = 0
		If item.Bouncing = 1 Then
			item.bounce:+6
			If item.bounce > 359 Then item.bounce = 0
			f = Sin(item.bounce) * 8
			a = Sin(item.bounce) * 6
			End If
		If item.Screen = Screen Then DrawImage ItemsGFX, item.x, item.y - f, item.whichtype
	Next
End Function

No need to "reset" bounce everytime.

What happens if your bounce would reach 362? I know, with "+6" you will reach 354 and then 360 ... but you might change the speed and voila...
Sinus returns the same value for 180 and 360+180 ... so you could just add 6 ... until not bouncing anylonger.
your method might result in a small "hickup": if "bounce" would be 362, then f would be similar to sin(2)*8 - but you set it back to sin(0)*8, which is something different. This might be visible as a small displacement-error (it does not rotate that smooth).

Is variable "a" even used? seems not... .


Think you should fix that "jiggy" issue first in a small code file ... and extend your code from there ... clean up the structures if you plan to make the game a bit bigger than just 4-5 screens.

ScreenManager
Screens
ScreenTransition

Item with custom functions/information (to handle combine with other items, descriptions, use-with-information).

AnimationData (which takes care of "animation frame", "next animation data", updating including delays).

RessourceManager (Loadingscreen, Collection managment, ...)
Ressources (Backgrounds, Sounds, ...)

But first fix the basic engine: rendering and updating.

Even If you do not split rendering and updating in the loop, try to split in in the classes - you might have to write a bit more code, but all in "render" is then just for displaying, while the checks (eg. collision, interaction ...) is done in "update".

Benefit: you could even run the game on slower machines (just decrease rendering) while keeping the updates high enough to not miss collision, clicks on items ...).


Also take into consideration to split up controls from logic. So instead of "if keyhit(key_left) then posX :- 1" you should think of "if keyhit(key_left) then Figure.MoveLeft()". This enables eg. the addition of "Joypad support" or other things (if you intend to do that). If not, ignore that paragraph.

bye
Ron


Sokurah(Posted 2014) [#23]
Thanks for the reply.

Yeah, not all things are equally good under the hood, lol.


A few comments to your comments...


"incl/soundrwapper.bmx":
cannot compile it ...maybe using a framework makes it hmm less compatible (you should really use "superstrict" and import things in individually imported files).


I'm not too worried about the sound code. That's easy to fix (and easy to strip out if there's a problem compiling it). That being said I have a soundwrapper (somewhere) that compiles on OSX - one that doesn't use fmod but allows me to use the same commands and let things work with minimal changes...but I must've gotten the files mixed up somehow. :-/

"Type Snow" - it could contain "addSnow" and other functions too.

I do "import things in individually imported files" - but I bunged everything together in this demo to simplify things. My mainfile is closer to 500 lines than the 150 lines in this demo and the rest of the game is spread out over about 30 files in the INCL folder, so everything is neatly categorized - all code handling items in one place, particles, enemies, etc in others. But yes - I probably should make it more OOP in structure. But then again - it works anyway. ;-)

The 'ShowPlayer' function sucks - I know. I didn't plan things well from the beginning and kept adding to it so I know it's a huge mess. A terrible terrible mess. It's by far the worst bit code in there and I was planning on rewriting it under all circumstances. ;-)


Why so complicated?

Global WorkingFrameSequence:Int[] = [0, 0, 0, 1, 2, 3, 3, 4, 4, 3, 3, 4, 4, 5, 6, 7, 8, 9, 0, 0]



About that: Yes, I know my way was too complicated. For some reason I didn't think of your way of doing it the first time I needed it, so I wrote it like this, and just copy/paste/edited it the following times I needed it.
Your way is a nice bit of optimization and I'll fix it - AND make sure to do it that way in the future. ;-)

Now that you mention it the 'ShowItems' code is pretty stupid too. I wonder why I did it like that? ...well, my excuse is 'beer'. :-D I can certainly do better (and have...but in other places apparently). :-D

The game currently has about 20 screens (aiming for about 60) and loads of puzzles already. I'm happy with most of my stuff. Granted, some portions could do with a serious rewriting and some could do with some optimizing too, but I'm too far ahead to rewrite from the beginning. Still, you've given me some good ideas and I'll see how many I can implement.
...I just hope I can fix that annoying jittering too. Perhaps it's time to finally look into that deltatiming-thing. ;-)

Again, thanks for your comments.


zoqfotpik(Posted 2014) [#24]
This is a very ambitious project. Ordinarily I'd ask if you might have bitten off more than you could chew but I think you can probably chew it. With something that big you might want to do your refactoring now rather than later.

I'm still wondering if you're running something in the background that might be causing slowdown. My Blitz installation, and Monkey, and other Blitz installations I've had, are surprisingly sensitive to having a number of tabs open in Google Chrome, presumably because of flash but maybe there is some other reason.

Another point: If you have a particle system, like for snow, you might want to encapsulate that into a manager class that uses an array for internal data representation instead of a list. Lists in Blitzmax seem to be surprisingly good but you want to minimize use of the garbage collector. Particle systems are a great use for a stack because you don't have to be constantly garbagecollecting dead nodes, they just sit there in your pool and get reused. If you really want to go whole hog with arrays, do it the old way with separate arrays for each property of a particle instead of using classes. Then don't use external functions at all in the particle system manager but do it all with inline code. For fairly simple particle systems that will work fine and you may see a fairly substantial speedup if you are using lots of particles. If you aren't using large numbers of particles the speedup isn't worth bothering with.


Sonic(Posted 2014) [#25]
this project looks great. my dad was a scriptwriter who wrote for Tom Baker / Peter Davison era Who (i used to sit on Baker's knee between takes!), and i'm also a massive p'n'c fan, so i heartily approve!