Monday, April 23, 2007

On Windows CE, Microsoft, the framebuffer, backwards compatibility, and demons

This was originally posted at Ternary Software. It is mirrored here because I wrote it and I want it on my personal blog as well as my work blog.

I spent the better part of today struggling to get some fancy graphics on my O2 XDA Exec (read a review if you are interested in the device). I know that I can use the Windows CE GDI to draw the graphics on the screen. I also know that will be slow. Not necessarily too slow, but certainly not an API that any self-respecting game developer would use. So, moving along, I knew that there was the GAPI - the Game API. It sounded great - provide access to the framebuffer and to low-level keyboard functions. So I read and implemented.

Everything was working fine in the Pocket PC emulator. But on a real device, no luck. It ran, but incorrectly. For one, it pretended that my device had a resolution of 240×320 pixels, which is 1/4 of the actual number. It used pixel doubling to fill the whole screen. On top of that, it wouldn’t draw anything in the leftmost pixel column. I had an ugly blue column extending from the top of the screen to the bottom.

I spend hours looking for a solution. I looked to see if it was a clipping problem, an API misunderstanding, a device issue. I couldn’t find any information. Then, I started reading support forums for other applications. It was there that I discovered that the problem is that, at this point, GAPI is provided on new devices as an emulation library. Apparently, in the Pocket PC 2002 / Windows Mobile 2003 days, GAPI was the way to make games. However, a lot of game developers made a lot of assumptions about transient things like, say, the screen resolution of devices. Microsoft, fearing that high resolution screens would break a lot of existing applications, decided to release a GAPI implementation for more recent devices that doesn’t return a pointer to the ACTUAL framebuffer. Instead, the application gets a pointer to a back buffer. Upon calling GXEndDraw(), a GAPI function whose purpose should be reasonably obvious (it flags that drawing operations are complete), this emulation library flipped the buffers and (on my device), upscaled all of the pixels.

HOWEVER, certain crafty game developers apparently thought that GXEndDraw was a useless function. After all, it didn’t seem to do anything on their Windows Mobile 2003 devices. And, if it doesn’t do anything, why should they take the time to call it? I believe that this is why I was having trouble with Pocket Quake. I plan to try to fix it and then tell the developer.

As for the single unwritable column of pixels, I simply think that this is a bug in the copy of gx.dll (the GAPI runtime library) that is on my device. The pixel doubling routine is probably wrong. I believe this because I think I have solved my problem. I can write all 480×640 pixels, including that annoying leftmost column.

To perhaps save somebody else the time that I just spent, let me share my findings. Microsoft suggests using the GETRAWFRAMEBUFFER escape operation in the GAPI Legacy Support section of “Developing DPI-Aware Applications”. There’s a good example in that article. This seems to be the new way to really, definitely, for sure this time, get raw access to the framebuffer. Until some developer takes too many liberties with it, and Microsoft has to invent yet another hack to keep other people’s applications working.

I should probably just bite the bullet and use DirectDraw. I thought that I had read on the GAPI for Handheld PC’s page that DirectDraw was not supported on the PocketPC platform, but they were perhaps referring to the 2002/2003 platform. I don’t see DirectX dlls on my device, but perhaps they are hiding.

Perhaps I’ve read so many of Raymond Chen’s posts that I’ve started to sound a little like him.

No comments: