I finally checked my mail today, and the 2GB memory kit I ordered for my laptop had arrived. I installed it earlier this evening—which involved removing five screws and taking off the wrist rest—and it made a noticeable difference in performance. $50 well-spent.
Indoor temperature at Armature Studio: 66.3°F.
Hard freeze coming to Austin area tonight. Awesome. Good thing I don't have to be outside... :|
It was particularly cold this morning, in the mid-thirties, though I forgot to check the thermometer in my car on the way in. You would think it was winter or something.
On the plus side, it's clear and sunny outside.
Before heading out Saturday evening to have dinner with my parents, I copied the Battlezone D3D9 source tree to my laptop so I could work on it at my parents' house afterward. When I ran it to make sure it worked, I got an atrocious 2-3 frames per second but I didn't have time to investigate at that point.
Later that evening, I spent some time looking into what was going on. Profiling revealed that it was spending an inordinate amount of time waiting inside the operating system. After reading through the D3D documentation, I came to the conclusion that I must be submitting the geometry data wrong.
There are two ways to lock dynamic vertex and index buffers: D3DLOCK_DISCARD, which discards existing contents and is best for submitting large batches of data (like entire models), and D3DLOCK_NOOVERWRITE, which promises the driver that new data does not overwrite existing contents and is best for submitting small batches of data (like single primitives). I chose the former because it was much simpler, and the renderer writes data into the locked buffer until a render state change forces it to draw the batch. The problem is that state changes crop up much more often than I expected, with a surprisingly large number of batches consisting of one or two triangles.
Changing the renderer from discard to no-overwrite was a major hassle, taking several hours, but the result was worth it: The frame rate increased by a factor of fifty to a much more acceptable 100-150.
I finally got full screen mode working properly.
Getting the shell to render in full screen mode was the trickiest part. Reading through the documentation, I found I could get a GDI-compatible draw context from the back buffer with GetDC(). I then spent six hours modifying the shell to use that draw context before discovering that I could just use SetDialogBoxMode on the device. It wasn't a complete waste, though, since I learned how the shell works and how to fix its visual glitches.
Responding to D3DERR_DEVICELOST and D3DERR_DEVICENOTRESET involved rearranging some code in the renderer, including creating a new device reset function sharing present parameters with the existing device create function. All the magic happens inside the D3D "blit" function that presents the back buffer. If the D3D device Present() method returns the device lost error, I set a flag that disables rendering to avoid D3D error spam. Subsequent attempts call TestCooperativeLevel until it returns the not-reset error, performs a device reset to get everything going again, and clears the flag that disables rendering.
Reset was not particularly difficult once I figured out what the D3D debug runtime was trying to tell me. Before calling device Reset(), I had to release references to all non-managed resources. I already knew I had to release the dynamic vertex and index buffers used by my execute buffer substitute, but I also had to release the pointer to the back buffer. Once that was done, Reset() worked precisely as advertised. After restoring the non-managed resources and render state flags, the renderer could proceed as if nothing had happened.
The neatest thing about Reset is that it's not just for device loss. It's also good for changing presentation parameters at run time. I use it when changing resolutions instead of the original technique of tearing down the renderer and rebuilding it.
- Mood:
accomplished
While nothing accumulated, Austin got some good snow flurries mid-day. The temperature plummeted this evening, with the thermometer in my car reporting 34°F on the drive home.
Support for full screen rendering in Battlezone is nearly done, though resolution switching doesn't work yet and the application hangs on device lost instead of recovering properly.
I also found out that getting the shell to work in full screen was as simple as turning on GDI support with IDirect3DDevice9::SetDialogBoxMode. Of course, I discovered that after spending six hours trying to get the shell to draw into the back buffer... :|
I fixed the shadow ground sprites and enabled anisotropic filtering for improved texture detail. The terrain looks a lot crisper now.
Now I have to do the thing I've been dreading: get full screen working again.

Getting textures to work was not too difficult. Once again, D3D9 was far simpler than the original.

It was brought to my attention several weeks ago that Battlezone's hardware renderer fails in Windows 7, both 32-bit and 64-bit. I put off doing anything about it for a while, but finally started investigating. After discovering that it flamed out deep inside D3D Execute Buffer calls, I decided the best solution was to replace the old DirectX 3 implementation with DirectX 9. I knew going in that it was not going to be easy...
The first challenge was to replace the old D3D setup code, since that portion of the DirectX API has changed drastically over the years. Creating a D3D device is remarkably simple now, and it even creates all the needed rendering surfaces for you.
The second was to replace the Execute Buffer. That turned out to be less complicated than I expected, since the individual operations are relatively simple, and generally have straightforward equivalents. The new low-level renderer uses a Vertex Buffer and Index Buffer to accumulate geometry data, flushing it with a DrawIndexedPrimitive call when primitive type, render state, or texture state changes. It may not be the fastest implementation, but it seems to work properly.
The two biggest tasks remaining are texture loading and full-screen display. After that, it'll be a lot of cleanup.

Posted by a former Pandemic employee on Facebook:
I was investigating why Battlezone 1 hardware rendering crashes on Windows 7 last week, and the Windows 7 Program Compatibility Assistant worked its voodoo on the release build. Now I can't run the application at all, since it crashes deep inside the compatibility layer before startup. Fantastic.
Renaming the application makes it work again, indicating that this is happening on the Windows side, not in the application itself. I'd like to clear the compatibility settings for bzone.exe, but haven't found a way to do that so far. The real solution would be to fix the crash in the compatibility layer, which is something only Microsoft could do.
I started a support ticket with Microsoft, but they basically suggested rolling back to a previous restore point. Considering it's been almost a week, that's not really an option.
The Bhut Jolokia pepper (a.k.a. ghost chili) is the hottest pepper in the world, at one million Scoville units. It's twice as hot as the Red Savina Habanero, the previous record holder. Naturally, some people have to try it for themselves...
I ported a subset of my 2D vector and matrix classes to C for Linley Henzell's upcoming project Transdimensional Hellspider, and it was a lot harder than I thought it was going to be. It's easy to forget just how much member functions and operator overloading streamline things until they're suddenly taken away from you...
One Million Ton Barabara
I'm not entirely sure what's going on, but the game seems to be an odd mix of Qix and Cannon Fodder with a team of saboteurs carving off chunks from giant airships before they can reach your city. The style is definitely interesting.
(I found this on Joystiq)
(I'm wearing my original faded-grey Pandemic shirt.)
