Xenocid
09.12.2002, 17:27
Tips for games and graphics in BREW on T720
I just spent a few days at the BREW labs at Qualcomm, and I learned several things (the hard way) about games and graphics in BREW. Here are the key points:
1. NEVER use any of the IGRAPHICS_xxx methods inside a game loop. One would expect that IDISPLAY_ClearScreen() and IGRAPHICS_ClearRect would operate at roughly the same speed, but it turns out that IGRAPHICS_ClearRect takes a whopping 150 msec to clear the screen! Poof, there goes your frame rate right there. IDISPLAY_ClearScreen() takes almost zero time by comparison.
2. Avoid image transparency at (almost) all cost. If you have any large transparent images, they will take forever to draw. It is much better to break up an image like this into several non-transparent images. Also note that BREW is not smart enough to figure out by itself whether the image is transparent. If you set the raster operation for IIMAGE_Draw() as IPARM_ROP=AEE_RO_TRANSPARENT, BREW will draw the image by checking each pixel for transparency, regardless of whether the image actually has transparent pixels. So only use this raster op for images that actually do have transparency.
In my game I have some transparent images representing game sprites, so transparency here could not be avoided. Typically it takes 10-30 msec to do transparent drawing of each sprite on the T720.
3. The timer implementation on the T720 is really screwed up. Just because you asked for a timer event 100 msec from now does not mean you will get one. In my original code that worked fine on the emulator, I would wait until the end of the timer callback to call SetTimer to ask for another timer callback for the next game frame. I asked for an amount of time equal to the frame rate (100 msec) minus the amount of time already spent executing the current game loop. This logic should give me a constant 100 msec frame rate, and in fact does just that in the emulator. But on the T720 device, this didn't work at all. I had to restructure my code so that I always called SetTimer again at the very begining of my timer callback. For some strange reason I still have not figured out (and the BREW labs engineers haven't figure out either), you cannot wait until the end of a timer callback to call SetTimer again. This works fine for animations without user input, but any user input ends up firing a whole bunch of EVT_KEY and EVT_KEY_HELD events that somehow block timer execution until the events are handled. This means that when you press a key, the game loop won't fire again until you release the key, ie the whole game freezes! I spent a good deal of time discussing this with the BREW lab people, who discussed it with Motorola who agreed that this was an issue with their (Motorola's) implementation of BREW on the T720. The timer issue was a nightmare to debug and to work around. What seemed to help get around the problem (in addition to moving SetTimer to the beginning of the timer callback rather than the end) was to check each EVT_KEY_HELD event and fire the timer callback anyway if 100 msec has passed since the last time the game timer callback was called. In other words, you can't always rely on the timer itself - sometimes you need to take advantage of a user event (like EVT_KEY_HELD) to check independently of the timer to see if it is now time to execute the callback.
4. As a general rule of thumb, the speed of running one game loop in the emulator running on a standard PC seems to be approximately twice the speed that you get on a real device. So if the emulator looks like it slow, the app on the phone (the T720) will run twice as slow as that. So a game loop on the emulator should only take 40-60msec worst case - otherwise the frame rate you get on the real phone will not be acceptable.
After working through all these issues in a series of nightmarish debugging sessions, I was finally able to get my game working on the T720. I could only get about 8 frames per second - specifically a frame rate of 120 msec was the best I could do. As a point of comparison, the J2ME game runs just fine on a Cingular (GSM) T720 at 10 frames per second (100 msec frame rate). J2ME of course was much easier to use to create the game, and unlike BREW all the J2ME APIs worked as advertised.
Hopefully this advice is useful to other game developers and will help you avoid BREW's undocumented pitfalls that result in many hours or days of wasted debugging. If anyone has any additional tips, I would certainly be interested in hearing about them.
I just spent a few days at the BREW labs at Qualcomm, and I learned several things (the hard way) about games and graphics in BREW. Here are the key points:
1. NEVER use any of the IGRAPHICS_xxx methods inside a game loop. One would expect that IDISPLAY_ClearScreen() and IGRAPHICS_ClearRect would operate at roughly the same speed, but it turns out that IGRAPHICS_ClearRect takes a whopping 150 msec to clear the screen! Poof, there goes your frame rate right there. IDISPLAY_ClearScreen() takes almost zero time by comparison.
2. Avoid image transparency at (almost) all cost. If you have any large transparent images, they will take forever to draw. It is much better to break up an image like this into several non-transparent images. Also note that BREW is not smart enough to figure out by itself whether the image is transparent. If you set the raster operation for IIMAGE_Draw() as IPARM_ROP=AEE_RO_TRANSPARENT, BREW will draw the image by checking each pixel for transparency, regardless of whether the image actually has transparent pixels. So only use this raster op for images that actually do have transparency.
In my game I have some transparent images representing game sprites, so transparency here could not be avoided. Typically it takes 10-30 msec to do transparent drawing of each sprite on the T720.
3. The timer implementation on the T720 is really screwed up. Just because you asked for a timer event 100 msec from now does not mean you will get one. In my original code that worked fine on the emulator, I would wait until the end of the timer callback to call SetTimer to ask for another timer callback for the next game frame. I asked for an amount of time equal to the frame rate (100 msec) minus the amount of time already spent executing the current game loop. This logic should give me a constant 100 msec frame rate, and in fact does just that in the emulator. But on the T720 device, this didn't work at all. I had to restructure my code so that I always called SetTimer again at the very begining of my timer callback. For some strange reason I still have not figured out (and the BREW labs engineers haven't figure out either), you cannot wait until the end of a timer callback to call SetTimer again. This works fine for animations without user input, but any user input ends up firing a whole bunch of EVT_KEY and EVT_KEY_HELD events that somehow block timer execution until the events are handled. This means that when you press a key, the game loop won't fire again until you release the key, ie the whole game freezes! I spent a good deal of time discussing this with the BREW lab people, who discussed it with Motorola who agreed that this was an issue with their (Motorola's) implementation of BREW on the T720. The timer issue was a nightmare to debug and to work around. What seemed to help get around the problem (in addition to moving SetTimer to the beginning of the timer callback rather than the end) was to check each EVT_KEY_HELD event and fire the timer callback anyway if 100 msec has passed since the last time the game timer callback was called. In other words, you can't always rely on the timer itself - sometimes you need to take advantage of a user event (like EVT_KEY_HELD) to check independently of the timer to see if it is now time to execute the callback.
4. As a general rule of thumb, the speed of running one game loop in the emulator running on a standard PC seems to be approximately twice the speed that you get on a real device. So if the emulator looks like it slow, the app on the phone (the T720) will run twice as slow as that. So a game loop on the emulator should only take 40-60msec worst case - otherwise the frame rate you get on the real phone will not be acceptable.
After working through all these issues in a series of nightmarish debugging sessions, I was finally able to get my game working on the T720. I could only get about 8 frames per second - specifically a frame rate of 120 msec was the best I could do. As a point of comparison, the J2ME game runs just fine on a Cingular (GSM) T720 at 10 frames per second (100 msec frame rate). J2ME of course was much easier to use to create the game, and unlike BREW all the J2ME APIs worked as advertised.
Hopefully this advice is useful to other game developers and will help you avoid BREW's undocumented pitfalls that result in many hours or days of wasted debugging. If anyone has any additional tips, I would certainly be interested in hearing about them.