The BREW Bag Of Tricks How to deal with inconsistencies and firmware bugs in BREW phones during game development by Guido Henkel, CEO [email protected] G3 Studios – http://www.g3studios.com Game Developers Conference 2005 1 Introduction Over the past year or two the half-life of a BREW handset has shrunk from somewhere around 1 year to about 4 months. That means any handset coming to market now is bound to be outdated and off the shelves in about 8 – 10 months At the same time carriers like Verizon Wireless are adding new handsets to their line-up at a heartstopping pace. The pressure to create and bring new handsets to market in ever shorter amounts of time is enormous As a result handsets that had insufficient testing and are riddled with firmware bugs have become the frightening reality of BREW development Game Developers Conference 2005 2 Introduction It is impossible to cover all problem areas you may encounter while developing BREW applications, so the examples I will give here are really just random samples that I have encountered and dealt with Game Developers Conference 2005 3 Pearl Of Wisdom Use as little of the BREW API as possible! Game Developers Conference 2005 4 Pearl Of Wisdom The less you rely on the BREW implementation the less you will be subject to firmware bugs and software issues. Create your own framework and implement most of the functionality yourself. That way you have full control over it and you can make sure the implementation is properly running on any handset In my BREW games, I usually use only a handful of of BREW API calls, such as IFILE – to read and write data including BAR files ISOUNDPLAYER – for sound output IHEAP – only selected functions for my own memory handler IBITMAP – only selected functions to obtain IDIB and native color info IDISPLAY_UpdateEx() – to render the framebuffer ISHELL_SetTimer() ISHELL_CloseApp() ISHELL_CreateInstance() Everything else I implement manually, including things such as the STDIO helper functions – strcpy(), memcpy(), atoi() etc. Game Developers Conference 2005 5 The Font Front Menuing, text output and text input are broken on a large number of handsets They also do not give you any control over the screen layout since fonts, kerning, line spacing and visual presentation vary from handset to handset. The ISTATIC API in particular is completely broken on various handsets, including the Samsung A610 and LG vx6000, and occasionally carriers won’t even accept applications that make use of the ISTATIC API on those handsets To solve this problem and to avoid the firmware bugs in these APIs I recommend writing your own text output and menuing classes. These are very easy to do and give you a consistent look across handsets. They are predictable and expandable and you can make them as simple or as elaborate as you need them Game Developers Conference 2005 6 Pixels Of Doom Although most handsets have a 16-bit color display model, the introduction of the Motorola v710 introduced a new set of problems. It is using an 18-bit color depth, represented as a 32-bit RGB888 model Using a dedicated datatype for all pixel operations solves the problem very quickly and without any code changes For 16-bit displays, simply define your pixel like this typedef unsigned short mypixel; While for 32-bit displays you could define it like such typedef unsigned int mypixel; If you consistently use your custom pixel data type to do all display related operations the compiler will automatically create the proper memory layout for you. All it takes is a simple re-compile Game Developers Conference 2005 7 Kyocera vs. The Bitmaps Kyocera BREW phones have a firmware bug that propagates through ALL their models. From the KX414 all the way to the KX2 Their phones allocate twice the amount of memory that is actually needed when you make calls to CONVERTBMP() or IBITMAP_CreateCompatibleBitmap(), quickly eating away your precious and all-too-sparse memory resources Depending on which SDK version you are developing for, there are ways to get around this Game Developers Conference 2005 8 Kyocera vs. The Bitmaps In BREW 1.1 it requires you to essentially hack into the native bitmap format of the handset and write your own CONVERTBMP() implementation which allocates the proper amount of memory. I do have a replacement module of CONVERTBMP() for these phones that I am licensing for a nominal fee In BREW 2.0 it is much easier as you have access to the handset’s native bitmap format through the documented IDIBs. Here you can easily write an own implementation of IBITMAP_CreateCompatibleBitmap() to solve the problem since all the function is doing is creating an IBITMAP/IDIB object and associating it with memory to hold the bitmap Game Developers Conference 2005 9 The Sound Of Music There are a few notable issues associated with the ISOUNDPLAYER API on a variety of phones. While some of them are easily fixed or avoided, others are sadly complete show stoppers Samsung handsets for example are unable to pause and resume MIDI tracks. A call to ISOUNDPLAYER_Resume() is simply ignored and silence will prevail. What’s even worse is that a call to ISOUNDPLAYER_Pause() will not do anything either. The audio will continue to play, wreaking havoc on incoming calls. This problem can also be found on a variety of other handset A solution to this problem is to simply use ISOUNDPLAYER_Start() and ISOUNDPLAYER_Stop() in their stead. While you can do that selectively only on handsets exhibiting the problem I found it much safer to completely remove ISOUNDPLAYER_Pause() and ISOUNDPLAYER_Resume() from my code base Game Developers Conference 2005 10 The Sound Of Music If you use the ISOUNDPLAYER API to also play back MIDI sound effects, you may have noticed that on a number of handsets restarting a sound effect will create a clearly audible popping/cracking sound, especially when you have some rapidfire sound effects being played back consistently This is a timing problem inherent in the audio architecture of each handset. To avoid the cracking sound simply create a moment of silence before starting a new MIDI effect. I do this using a short delay timer that keeps the API idle for a variable amount of time. This delay ranges anywhere from 0ms on some handsets all the way to 300ms on the vx4400 Game Developers Conference 2005 11 The Sound Of Music Many Nokia phones have also serious issues with the ISOUNDPLAYER API resulting in most games for these handsets being mute. One of the issues is that it is impossible to loop MIDI tracks using the API The firmware of these phones has a bug that consistently shoots messages to BREW and your application, indicating that it has completed playing back a MIDI track, even though it has just yet started. These rapid-fire events will stall the handset and in many cases cause it to actually reset if they cannot be processed fast enough by your application I have been working with Nokia to isolate the problem and fortunately it has been fixed in the latest handsets, such as the 6255i. On all earlier phones however there is no work-around available to the best of my knowledge Game Developers Conference 2005 12 The Sound Of Music On top of these API errors a large number of handsets do not properly report the volume keys to the operating system. As a result, sadly, on these handsets it is impossible to actually adjust the volume unless you will do it programmatically with a useradjustable slider To make matters worse, some of these handsets in particular are playing back sounds at a deafening volume. In these cases it may be necessary to adjust the volume programmatically Game Developers Conference 2005 13 The Sound Of Music Even if you handle audio volume from within your application you will find that some handsets simply ignore the ISOUNDPLAYER_SetVolume() command. On the vx4400 and t720, for example it is impossible to adjust the volume at all On other handsets you may find adjusting the volume does work but has unwanted side effects, such as affecting the phone’s user settings, so make sure to use the ISOUNDPLAYER API with a bit of suspicion at all times Game Developers Conference 2005 14 Memoirs of the Invisible Memory Despite its many strengths, the Audiovox CDM-8900 can be quite a challenge for game developers. With a display of 128x146 pixels it requires a bit of memory to do back buffering, soft scrolling etc on this handset. Unfortunately despite it being listed as having 500kB of RAM, the handset offers up much less for BREW applications and you will find that you actually have only about 440kB at your disposal on this handset In order to make more room on this handset I reverted to a simple trick Game Developers Conference 2005 15 Memoirs of the Invisible Memory After doing some research I noticed that the handset allocates a significant, permanent buffer of about 12kB the first time you access your BAR file. This is done in order to buffer the directory structure of the BAR file I presume and to buffer the input stream By replacing BREW’s ISHELL_LoadResData() function with my own implementation I was able to reduce this memory footprint to 1kB Additionally, working with bitmaps in palettized 8-bit format as opposed to fully expanded native 16-bit can sometimes be very useful, especially if the image is not rendered very frequently. There is a significant performance hit for a blitter-routine that does on-the-fly 8-to-16bit conversion because of the cache thrashing, but if you really need to save some memory, this is one way to go about it Game Developers Conference 2005 16 Memoirs of the Invisible Memory The Audiovox CDM-9900 has a large display with 240x292 pixels. The problem with this phone is that there is insufficient heap memory to do anything sensible with it The handset is listed as having a meager 640kB of RAM which is ridiculous considering that the display itself takes up about 140kB. Whatever you do you will always be severely strapped for memory on this handset and the only way I was able to alleviate this was by rendering my apps into a 120x146 pixel backbuffer and then scaling it up in real time just in time before the display refresh Game Developers Conference 2005 17 Stay With Me There is a major issue with the IWEB interface that is not documented. If you pass a URL to the API that is located in the local scope, IWEB calls will fail because the variable doesn’t stay around long enough for the respective callback calls inside the OS. URLs have to be global to the application in scope! This version does not work… void ReadFromServer( applet *curApp, const G3string *fileName ) { G3string buffer[128]; StringCopy( buffer, (G3string *)"http://www.somedomain.com" ); StringCat( buffer, fileName ); curApp->ConnectionStatus = CONNECTION_IDLE; G3_DESTROY_ARRAY( curApp->ConnectionBuffer ) // Free existing connection buffer IWEB_GetResponse( curApp->HTTP, ( curApp->HTTP, &curApp->HTTPResponse, &curApp>Callback, (const char *) curApp->Scratch, WEBOPT_END ) ); } Replacing buffer[] with a global instance in the applet scope will fix things Game Developers Conference 2005 18 I Saw What You Did When writing your own blitter routines make sure to always, always properly clip your blits. Do not rely on the handset to do any clipping for you Handsets like the t720 and vx4400 among others have firmware bugs that cause the handset to crash in this area if you attempt to blit to negative x-coordinates or to a coordinate outside the physical display area. Clipping is trivial, takes only a few lines of code and should be part of every industrial strength blitter routine Here’s a brief example for clipping x-coordinates if ( xPos < Clip.left ) { width += xPos - Clip.left; xSrc -= xPos - Clip.left; xPos = Clip.left; } if ( ( xPos + width ) > ( Clip.left + Clip.right ) ) { width = width - ( xPos + width - ( Clip.left + Clip.right ) ); } Game Developers Conference 2005 19 Coffee Is For Closers With the BREW 2.0 SDK Qualcomm introduced the concept of IDIBs, which give programmers direct access to the native bitmap data of a handset. Sadly however, IDIBs are not supported by all handsets. The Audiovox CDM-9900 as well as Kyocera’s KX1 and KX2 handsets, for example, do not allow applications to retrieve the IDIB interface of a bitmap Fortunately there is a work-around. An IDIB is in reality nothing more than a public interface for BREW’s IBITMAP object. It has no actual functionality and only exposes the contents of the IBITMAP object to the application. With that in mind an IDIB interface can simply be created using a static cast that looks something like this IBITMAP_QueryInterface( imgBuffer, AEECLSID_DIB, (void **) &imgPixels ); if ( NULL == imgPixels ) { imgPixels = (IDIB *)imgBuffer; } Game Developers Conference 2005 // If device doesn't support // the IDIB API, simulate it! 20 I See You, Now I Don’t The concept of dirty rectangles has been a valuable part of BREW’s display update routines particularly on lower end phones. With the introduction of BREW 2.0’s IDIBs and the direct memory access they provide, dirty rectangle algorithms can quickly become traps on handsets such as the LG vx6000, LG vx7000 or the CDM-9900 Due to firmware bugs these handsets do not properly recognize when an application is directly writing to the display’s frame buffer. As a result the dirty rectangle algorithm oftentimes prevents the display from doing a proper redraw You can use a few simple lines of code to force the handset to mark the entire screen dirty. Simply draw a pixel in the upper left and one in the lower right corner of the screen using a BREW API call NativeColor color = IBITMAP_RGBToNative(DeviceBitmap, MAKE_RGB( 0, 0, 0 )); IBITMAP_DrawPixel( curApp->DeviceBitmap, 0, 0, color, AEE_RO_XOR ); IBITMAP_DrawPixel( curApp->DeviceBitmap, 239, 291, color, AEE_RO_XOR ); Game Developers Conference 2005 21 Faster, Pussycat! If you have an application that is fairly processing-intensive you may notice that on lower end handsets key presses are delayed and not immediately reported In order to avoid this problem I give the OS more time to breathe by staggering execution of program parts. The application is doubling the event timer frequency to relinquish control to BREW more often and then flip-flops between executing game play and rendering code. I found that it dramatically increased the overall responsiveness of the handsets in question void GameEvent( applet *curApp ) { if ( 0 == curApp->FlipFlop ) { curApp->sasApp->run(); if ( 0 == curApp->DevCfg->FlipFlop ) { IDISPLAY_UpdateEx( curApp->a.m_pIDisplay, FALSE ); } else { curApp->FlipFlop++; } } else { curApp->FlipFlop = 0; IDISPLAY_UpdateEx( curApp->a.m_pIDisplay, FALSE ); } Game } Developers Conference 2005 // // // // // On some handsets we need to speed up the event timer in order to improve responsiveness and to satisfy the watch dog 22 Call Me A strange problem I once had on a few handsets was that incoming calls and SMS messages were simply ignored by the phone while my game was active. Interestingly the behavior was limited to particular screens within the application Some research into this showed that as in the previous example my application was simply eating up too much processing power, making it impossible for BREW to handle the incoming call. Lightening the work and rendering load in those screens in question solved the problem While the solution was simple it also shows that it is every important for you to test incoming calls and SMS in every screen you may have in your game, as each of them generates a unique load on the processor Game Developers Conference 2005 23 Maniac Cop A few Samsung phones are notorious for watch dog timer issues, in particular the a530 handset. The watch dog may kick in terminating your application despite the fact that there is nothing wrong with your application or the processing time it consumes There is a very simple solution to this problem which I found works in 99% of all cases. When you render your display, instead of using IDISPLAY_Update() use the function IDISPLAY_UpdateEx() instead and the watch dog will lie sleeping as it should IDISPLAY_UpdateEx() is recommendable on all phones, by the way, as it gives you more control over the rendering timing and thus ensures steadier frame rates Game Developers Conference 2005 24 Topsy-Turvy Some of the Nokia phones use big endian datatypes as opposed to little endian data that are used on most other BREW phones. While normally this isn’t a problem at all, it can become an issue if you are loading binary data from a file that has been prepared for little endianess Two small routines – one for 16 bit integers and one for 32-bit integers – can be used to change the endianess on the fly thus making it possible to use the same data sets for big and little endian platforms without change short SwapEndian( register short inVal ) { return ( ( inVal & 0xFF ) << 8 ) | ( ( inVal & 0xFF00 ) >> 8 ); } The endianess of a platform can be determined at runtime by writing an integer to memory and reading it back bytewise, checking the order in which the data bytes have been committed to memory Game Developers Conference 2005 25 The Good, The Bad And The Ugly Vibration is the Stygian Abyss of BREW handsets. It is unusable on virtually all handsets for a wide variety of reasons. While the BREW API allows you to define a vibration duration, the t720 for example ignores the parameter and will always vibrate three times in a row. Other handsets override the duration parameter and vibrate for an undefined period of time. Other handsets yet will stop all audio output as soon as they start vibrating or whatnot. The Audiovox CDM-8900 takes the cake in the vibrator-department however. It allows you to start vibration but there is no way stopping it. Not even powering it down will work. The handset will vibrate until the battery is removed. My recommendation - forget about vibration in BREW applications! Game Developers Conference 2005 26 One MIF Fits All MIF file settings are oftentimes a mystery to BREW developers, including the proper image sizes to include. Documentation on this end is spotty at best and also changes across carriers To create a MIF file that works for every handset, I always make sure my MIF file is edited and saved in the BREW 1.1 format. Since Brew is backward compatible this MIF format can be read on any handset and you can use this MIF file for each and every handset Regardless of what Device Data Sheets specify, I always use the same image sizes for the images to include. I use 26x26 pixel icons for the “Icon” and “Image” entry and a 16x16 pixel icon for the “Thumbnail” entry. Since no handset is making actual use of the large “Image” file, I am sticking with the bare minimum image sizes of all handsets and therefore am able to use such a MIF file for each and every handset Game Developers Conference 2005 27 License To Kill Also in regards to MIF files, a peculiar problem has surfaced on the LG vx6000 regarding licensing types. Occasionally you may want to adjust your demo mode of the game by using the PT_DEMO and PT_PURCHASE license types to see if the game has been purchased or not. On the vx6000 you have to be careful creating the MIF file that determines this setting Always make sure to create MIF files that contain licensing information using the 2.x MIF editors, saving the MIF file as 2.0 versions. If you save the MIF file as a 1.1 version the licensing information is corrupted and the application will be perpetually running in an unlimited mode. You are essentially giving away your game for free if it is provisioned that way on a carrier’s server! Game Developers Conference 2005 28 The Name Of The Rose Naming your application is key to its success. Since there is no presentation platform in BREW and users have to decide whether they are interested in a game or not solely by its name, choosing the right name is crucial It is possible to choose a name that is too long. Although there is no documentation on the subject and neither NSTL nor Qualcomm were able to provide me with accurate information, it seems that a length of 24 characters for an application name is the hard limit. Anything beyond that is exceedingly dangerous and freaks out various handsets. As a result the application will be be cancelled or may even fail True Brew Testing Limit your application names to 24 characters to be on the safe side! Game Developers Conference 2005 29 Roll Over, Lay Down On BREW 2.x handsets you may occasionally experience a strange behavior. When pressing the “CLR” key to terminate the application you may find that instead of returning to the phone’s BREW screen it actually launches the BREW shop. This behavior will cause your application to fail True Brew Testing so it needs to be addressed The solution is usually very simple. Make sure to handle your CLR key events in the EVT_KEY handler as opposed to the EVT_KEYPRESSED handler and the problem will go away However, do not handle all key events in the EVT_KEY handler, as some handsets require you handle them in the EVT_KEYPRESSED handler. Something like this works on all handsets… case EVT_KEY_PRESS: if ( AVK_CLR != wParam ) { keyPressed( curApp, wParam ); } retFlag = TRUE; break; case EVT_KEY: if ( AVK_CLR == wParam ) { keyPressed( curApp, wParam ); } retFlag = TRUE; break; Game Developers Conference 2005 30 Deadwood Connecting a handset to the PC and getting applications loaded using AppLoader can be a taunting nightmare. With so many handsets and USB cables your system will eventually run out of assignable USB ports and Qualcomm’s tools typically recognize only a small subset of these ports, making matters even worse. Add to that the nightmare of obtaining the correct drivers, rebooting your computer and handset countless times, and the driver collisions coming along with installing drivers for some 50 handsets and you’re soon reduced to a drivel One thing that has saved my sanity on many occasions in that respect is a SERIAL cable for the vx6000. The vx6000 communications port can almost be viewed as an industry standard and I know of at least 15-20 handsets from various manufacturers that you can use the vx6000 cable with without a hitch. It always connects – much faster than the USB counterpart – and best of all, it does not require a driver! It just works! Game Developers Conference 2005 31 Let Sleeping Corpses Lie One area of constant trouble as a BREW Developer are the emulator skins provided to developers by Qualcomm through their Extranet. Every developer I know has at one point or another stared at his application on the screen in disbelief, wondering what happened to his code that causes the application to create a completely garbled screen output In most cases it turns out that the emulator skin contains incorrect settings, such as incorrect parameters for display window dimensions, the display resolution, the color depth, the device ID or the memory settings. Therefore, before using an emulator skin for the first time, doublecheck its settings using the Device Configurator and set it up according to the information on the Device Data Sheet. Since the emulator doesn’t really emulate anything beyond these five skin settings these parameters are absolutely crucial Game Developers Conference 2005 32 Under A Glass Moon Sky In retrospect many of the issues I just discussed could have been avoided. In an ideal world I would wish that Qualcomm, OEMs and carriers would take a few steps to help minimizing such problems in the future. In order to achieve that, they should • Involve developers in pre-release certification and encourage their input • Openly document some of the data formats in use, such as the MIF and BAR formats to allow developers to write streamlined tools of their own • Create accountability in conforming with the BREW API so that it becomes everyone’s best interest to create BREW implementations that are fully functional Game Developers Conference 2005 33 Thank You! I would love to hear your ideas and tips from your own bag of tricks You can always contact me at [email protected] Game Developers Conference 2005 34
© Copyright 2024