LAG: Syncing problems in Neko+Cpp Targets



  • Hey you guys,!

    I keep experiencing lag on Neko/CPP targets. Cpp is my primary target and Neko is just being just for debugging and fast building to test code. So I really don't care mush for Neko but I do care for Cpp.

    I've posted on this topic before and I've posted this question on the OpenFL forum as well. Basically Cpp builds do not sync well with the hardware. I've made some test code for this. You don't need HaxeFlixel for this tests code, just OpenFL and Lime. Any version should work from old to new. (great for testing).

    Does anyone have a solution for this? Obviously I want this code to run without lag on Cpp targets. Any comments on this would be appreciated!. For me this is a breaking point. I rater use Haxe then something else right now but this must be fixed!

    package;
    /*
     OpenFL program to show lag. It runs great in HTML5 but Neko And CPP targets are laggy.
            You can use any version of OpenFL + Lime, but Flash only shows a empty window :S ?
    
         	If you start the program either lag is already showing or it may take a while.
         	Keep restarting the program, eventually lag will show. Also dragging the window in
         	MS Windows can introduce lag. HTML5 does not show any of this behaviour.!, So i'm
            guessing that SDL - implementation or SDL itself - is the culprit!
    
    		Please note that, resizing the stage is not implemented in this code, and
         	don't build with -debug! Debug targets can/may allocate new objects for debugging!
    */
    import openfl.display.Sprite;
    import openfl.geom.Rectangle;
    import openfl.display.DisplayObjectContainer;
    class Main extends Sprite {
    	// you can play around with these, but 200, 300 is heavily tested
    	// For windowed mode I use 1280x720
    	public static inline var kSize:Int			= 200;
    	public static inline var kSpeed:Int			= cast kSize*1.5;
    	var amount:Int;
    	var yoff:Float;
    	var instances:Array<Sprite>;
    	var colors:Array<UInt>	= [0xFF0000, 0x00FF00];
    	var col:Int=0;
    	var current:Int=-1;
    	var world:DisplayObjectContainer;
    	public function new () {		
    		super ();
    		world		= new DisplayObjectContainer();
    		addChild(world);
    		amount		= Std.int(stage.stageWidth / kSize)+2;
    		instances	= new Array<Sprite>();
    		yoff		= stage.stageHeight-kSize; // No subpixels, both are int.
    		for (i in 0...amount) {
    			newInstance(++current);
    		}
    		stage.addEventListener(openfl.events.Event.ENTER_FRAME, onUpdate);
    	}
    	function createSprite(color:UInt):Sprite {
    		var s = new Sprite();
    		s.graphics.beginFill(color);
    		s.graphics.drawRect(0, 0, kSize, kSize);
    		s.graphics.endFill();
    		return s;
    	}
    	function newInstance(column:Int) {
    		var s 	= createSprite(colors[col]);
    		s.x		= column * kSize; // no subpixels, both are int.
    		s.y		= yoff;
    		if (++col==colors.length) col=0;
    		instances[column]=s;
    		world.addChild(s);
    	}
    	function onUpdate(e:openfl.events.Event) {
    		moveWorldByDelta(1.0/60);
    		validateBuild();
    	}
    	function validateBuild() {
    		// Just math, no new Garbage() or "bad" + "string" + "concats"
    		var c:Int 	= Std.int((-world.x+(stage.stageWidth))/kSize);
    		var s:Sprite;
    		if (c>current) {
    			s = instances[0];
    			for (i in 1...amount) { // no iterator!
    				instances[i-1] = instances[i];
    			}
    			// No subpixels (both are int)
    			s.x = ++current * kSize;
    			instances[amount-1]=s;
    		}
    	}
    	function moveWorldByDelta(delta:Float) {
            // Delta is open for discussion. But i've tried any sane value for it.
            // Dynamic delta's, smoothing deltas, but Fixed Deltas (like this one)
            // Give nice results. Also when in VSync (assuming 60hz), fixed delta's
            // 1/60 should give best results. (don't forget that the caller/drivers can/will also
            // adept their syncs when it fall behind, there no reason to do this yourself.)
    
           	// some much refered reading: https://gafferongames.com/post/fix_your_timestep/
           	// a suggested variable delta 0.01 or 0.02 makes the rendering really shakky.
            // After applying that he interpolates the alpha, technically he's is just doing a
            // complexed dynamic delta: (current_frame_time-_previous_frame_time), with
            // overhead of potentially calling the physics multiple times instead of once.
           	// also in vsync this kind of methods should not be necessary, just use 1/refreshrate.
    
    	// Lets just say that even if 1/60 is inaccurate, then still the only real effect should
    	// be speed, and this should not result in lag!. Lag is created by not being synced correctly
    	// with the hardware. HTML5 syncs perfectly, CPP/Neko do not! Double Buffering is probably 
    	// not well implemented!
    
    		world.x -= Math.round(kSpeed * delta); // No subpixels!
    	}
    }
    

    Although the problem lies more in OpenFL/Lime then in HaxeFlixel, still, if anyone has any great ideas on this..!?

    Thanks!



  • I don't experience this lag you mention and I've been working with cpp/neko for about 2 years now. Or at least, isn't noticeable or a problem.

    However, I notice that when running in a window it might get choppy sometimes, but that's because of the update optimizations Windows tries to do. This is gone running in full screen mode. Not HaxeFlixel, OpenFL or SDL's fault, I noticed the same on other apps.



  • Well, i'm pretty much disappointed by this. And indeed, running it windowed or fullscreen matters. Fullscreen there seem to be no problems. Lots of other factors also seem to be responsible. Among them are:

    • Graphics card
    • Drivers (version)
    • Operating System
    • The code itself (but this example is pretty clean)
    • Dragging the window (give it a slight nudge seem to make it better or worse :)

    I've coded this same example in Monogame and LibGDX. Together with OpenFL they give somewhat different results. Also the HTML5 version of OpenFL is giving really good results. But it seems to be too heavy for mobiles. Monogame seems to run very well on the desktop but i dont like it on Mobiles. LibGDX is similar to Monogame only it performs a lot better on startup and initialization. OpenFL does better on mobiles.

    I'm not 100% sure what to do with all this. There is no all inclusive winner in my tests or solution for my problem. It seems that accepting it for what it is would be the best solution.... I do like Haxe and the general performance is great. Continuing seems like the best solution.!

    Anyways, thanks for your reply.



  • I have tested two different games on two different computers. The first game has lots of code inside of the update() functions. That game has many features and its code is not very optimized while the second game is lightweight and its code optimized.

    Both games were tested on an old computer and a cheap new computer. The first game on the old computer played at normal speed in flash, and slow in neko and very slow in cpp while the lightweight game played fast in flash, neko and cpp. The first game on the new computer was somewhat slow in flash and played a bit slow in neko and played fast in cpp while the lightweight game once again played fast in flash, neko and cpp. if the game code is heavy and there are lots of code in the update() function or the code is cpu extensive then there could be a delay in the speed of the game.

    if after you optimize the code, there is still a delay in the speed of the game then you might give the option for the user to set the speed of the game by changing its framerate. this is not a bad idea as some users might like to play the game at a slower or faster framerate than others. the problem with changing the framerate is the game ticks. the ticks which is used to delay or to do an action when a tick value is reached, will not be delayed for the same length of time as another framerate. the following code addresses that problem. Also note that when using game ticks, haxeflixel likes the framerate to be in increments of 60.

    var ticks:Float = Reg.incrementTicks(ticks, 60 / Reg._framerate);
    
    /**
    * framerate ticks.
    * @param ticks	the current value of a tick.
    * @param inc	by how much a tick increments. 
    * framerate 60 = 1, rate 120 = 0.5, 180 = 0.33, 240 = 0.25
    * */
    public static function incrementTicks(ticks:Float, inc:Float):Float
    {
    	ticks = FlxMath.roundDecimal(inc, 2) + FlxMath.roundDecimal(ticks, 2);
    	ticks = Math.round(ticks * 100) / 100;
    
    	if (FlxMath.roundDecimal(inc,2) == 0.33)
    	{			
    		var temp:String = Std.string(ticks);
    		var temp2:Array<String> = temp.split(".");				
    
    		if (temp2[1] != null)
    		{
    			if (StringTools.startsWith(temp2[1], "99"))
    			{
    				var temp3:Float = Std.parseFloat(temp2[0]);
    				temp3++;  ticks = FlxMath.roundDecimal(temp3, 2);	
    			}
    		}
    	}
    	
    	return ticks;
    }


  • Hi,

    Usually I increment the delta based upon the elapsed time. OpenFL does not seem to provide this, at least not on a ENTER_FRAME event. You can compute your own one with haxe.Timer.stamp(); Normally I do something like this. (typed on the fly, might have syntax errors)

    previous_frame_time  = current_frame_time;
    current_frame_time   = haxe.Timer.stamp();
    previous_delta       = delta;
    delta                = current_frame_time - previous_frame_time;
    smoothdelta          = (previous_delta+delta)/2;
    

    But how accurate is stamp()? And my main concern is that OpenFL is not in sync with VSync.

    SDL has 2 methods for Vsync. One builtin that needs to be setup correctly to work, the other is no Vsync in which case you can intruduce one yourself by setting a delay. (SDL_Delay is off though, and needs to be corrected with a while loop).

    I'm pretty sure that the problem lies in OpenFL. Ive done some test in Monogame and LibGDX. The render better on Windows. I'm coding an example in SDL as we speak, just to see what happens.

    Anyways, thanks for you reply.



  • @galoyo said in LAG: Syncing problems in Neko+Cpp Targets:

    if after you optimize the code, there is still a delay in the speed of the game then you might give the option for the user to set the speed of the game by changing its framerate. this is not a bad idea as some users might like to play the game at a slower or faster framerate than others.

    This^

    Recently, a super nice youtuber willing to play my humble game stumbled upon this problem. Certain recording software can get the recording choppy, with uneven framerate, or slow to a crawl. We fixed this by adding an option to lock the game to 30 fps and enabling frameskip, with great results!

    In case someone is wondering how that can be achieved, is simple:

    FlxG.drawFramerate = 30;
    FlxG.updateFramerate = 30;
    FlxG.fixedTimestep = false;
    

    BTW: sometimes is possible to have choppy, jumpy movement even tho you are having great performance. I can't yet understand why, but has something to do with super.update() call. For example, there might be sightly movement differences between this:

    Update(elapsed)
    {
    movementCode();
    super.update(elapsed) ;
    }
    

    ... and this:

    Update(elapsed)
    {
    super.update(elapsed) ;
    movementCode();
    }
    

    Play test in game to see what gives you the best results!


Log in to reply
 

Looks like your connection to HaxeFlixel was lost, please wait while we try to reconnect.