View Single Post
  #1  
Old 2018-08-12, 04:52
jhl jhl is offline
Magic Level: Yellow Ball
 
Join Date: Aug 2018
Posts: 6
LbaWin low power patch

I recently dug out LBA for the first time in a few years... and a few minutes in, my laptop fan was going nuts and my battery was fading fast. It was so annoying I had to crank the sound up to mask it! For a game engine from the mid-'90s this seemed like something was a bit wrong. Given that I actually wanted to be able to play more than 20 minutes on a charge, I did a bit of reverse engineering to figure out how to calm it down a bit. Here's what I did and what came out, I'd be interested to hear if anyone else finds this useful. I know "here I patched it" can mean all sorts of things, so I'm going to explain exactly what I changed and you can decide how you feel about it

As with most software of the era, LbaWin uses 100% of the CPU regardless of how busy it is; it spends all its time checking for new input a squillion times a second. With those computers it wasn't a big deal, but now that so many of us have moved to mobile devices, it's a little troublesome for the user experience.

Interestingly, LbaWin already has an FPS limiter: according to the change notes, the FPS was limited to 500 to avoid problems with collision detection. Here's the FPS limiter code in LbaWin.exe:

It loops over and over, checking the inputs, until it's time for the next frame - using 100% CPU. Then it sets the next time 2ms in the future, to get that 500FPS limit.

This is easy to fix: we just need a little sleep in that loop. Even a sleep of just 1ms would do the job. Of course, there's no empty space here to insert some code, so it's got to go elsewhere; and perhaps more importantly, this isn't the only place the game spins in a tight loop.
It turns out that this loop governs the main rendering when you're running around in the world, but there are other loops that take over during dialogue, for example. If we just patch this loop, the fan still cranks up while you're listening to people talk! Also annoying.

Luckily, the answer lies in the polling routine sub_4034A0. This is called from most places where the game spins waiting for timers or input. It looks like this:

sub_4036D0 does housekeeping related to FPS calculation and timers (and FPS display if you press F).
sub_4033E0 handles input from Windows' event system (so keyboard input, Alt+F4, et cetera). And it returns a flag indicating if the game has been asked to quit: if so, it calls into sub_403480, which exits the game.

As it happens, sub_403480, the exit routine, is placed just before this code:


Conveniently, this gives us a little space to work in. The exit routine calls PostQuitMessage before calling _exit, but this doesn't actually achieve anything, because _exit exits the process immediately.
So by cutting that out and moving the _exit call up a bit, we score a few free bytes of space to build something in...

So here's what I did: I replaced the call to sub_4036D0 to call the new empty space. There, I wrote a new function which calls Sleep() to sleep a few milliseconds, and then calls sub_4036D0 itself. (I also changed a few sub names on the way to this pic.)


In the end, I decided that running at 500FPS was also over the top, so I changed the FPS limit to 60FPS (waiting 16ms instead of 2ms between frames). This seems like an entirely reasonable limit for all purposes, but feel free to let me know if you have a strong opinion! It drops CPU usage by about 8x so that's pretty big.
Thus I chose to set the sleep in the loop to 4ms, so it should poll for input 3-4 times on every frame. Again, that should be more than enough for any usage, right?

Now the CPU usage is comfortably at 5-10% while playing on my laptop, the fan never runs, and I can enjoy the game properly

(I also had a problem with Wine; it was burning up another CPU in wined3d_cs_run() and I had to disable CSMT using regedit... not sure if that's a Wine bug or an LbaWin bug.)

Anyway, this scratches my itch; I'd be curious to hear if it's useful for anyone else.
Attached Files
File Type: zip LbaWin_lowpower.zip‎ (108.5 KB, 100 views)

Last edited by jhl; 2018-08-12 at 08:06. Reason: fix huge images
Reply With Quote