January 20, 2012 3 Comments
After a few days off, The Great Porting Adventure resumes!
The TODO list has reached equilibrium – new items are discovered at about the rate that I knock them off. I figure this is a good sign, since I’m getting a handle on the remaining work and the issues that do pop up are pretty minor. Porting is a bit of a grind though. I’d much rather be working on something new and exciting at this point. The novelty of seeing my game running a Mac has all but worn off and thus I didn’t spend much time on it this week.
I started by going through the list of things that I compiled out just to get the game running in the first place. The big one was the intro “studio logo” splash which was a screen with a bit of transition flair that shows up when the game starts and loads a bunch of assets behind the scenes. I had to basically rip this out at first because it was causing a crash somewhere in OpenGL, which was about two levels of framework lower than anything I understood.
I read into it a bit and it turns out that OpenGL does not like it when you use an OpenGLContext from a different thread. This was a straightforward fix (a MakeCurrentContext() in the right place in the worker thread) because my use case was pretty simple: main thread loads assets, worker thread updates and draws the logo animation. This fixed the crash, but rendering had some serious issues. The screen fade was functional, but debug text was popping in and out over top of it. The logo itself wasn’t showing up at all, even though it was drawn in a very similar way to the screen fade.
It would eventually be revealed that none of these issues were related to OpenGL nor my multi-threaded use of it.
I spent a while trying to figure this out and lamenting the lack of PIX. At one point in my debugging, I noticed that I was multiplying some Color values by an alpha that was outside [0,1]. This turns out to be a no-go in MonoGame. I didn’t look into it much (and I don’t have the source in front of me), but I’m guessing it has something to do with the packed value representation used for Color. Not sure – needs more investigation. Certainly not the source of problems I was expecting.
The inconsistent rendering order that was causing sporadic popping of components was due to the draw order not being respected in the Game class. Or rather, the implicit draw order based on the order you added components was not always being honored. I fixed this one by explicitly assigning a DrawOrder to my components, which fixed the sorting.
After a while wrestling with this, I realized that my loading scheme was really just overly complicated and kind of hacky. I had pulled it from a previous game that loaded a lot of things up front, but the use case for DLC Quest wasn’t the same. There was no need for a second thread, and there certainly was no reason that it should be calling Present() on the GraphicsDevice. I’m pretty sure it came from the NetRumble sample, but it still felt wrong to be circumventing the Game loop like that. At any rate, I ripped it out and switched to a much simpler “show logo animation, then press start screen, then load stuff” flow. Much better.
The fiddling continued as I worked to get rid of some “dirty frame” transitions. It seems like there are some cases where I need to clear the framebuffer that don’t crop up in the XNA version of the game. I’m not sure where the discrepancy stems from, but it was easy, cheap and pretty logical to add in a Clear in one or two places. One transition problem stemmed from my use of ResetElapsedTime() to avoid a hitch after spending a long frame loading content. This method isn’t implemented in MonoGame at the moment, but I didn’t dig deep enough to find out if MonoGame would try to “catch up” on long frames anyway. It was easier just to add a few more frames to smooth out the transition.
Oh, and SoundEffectInstance.Resume() was broken. But I fixed it.
I’ve also noticed that my game throws a bunch of errors on startup (possibly when loading Mono-related libs) that look a little like this:
DLCGame.Mac(3296,0xb0183000) malloc: *** error for object 0x253f1010: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug
I don’t think there’s a <sarcasm> tag powerful enough to say I’m looking forward to figuring that one out.
That’s about it for Day 8. It’s getting to the nitty-gritty and game-specific stuff now. Still haven’t looked at the Mac store requirements… one of these days…
Running total: 8 days, $112.87