Doom engine code review
fabiensanglard.net
fabiensanglard.net
2.7 million pixels per second at 35 fps (the cap).
1.4 million pixels per second at 18 fps (~50% of cap).
At the more realistic target of 18 fps, you have 24 clock cycles per pixel. A 486 averaged about 0.8 instructions per clock, so you're looking at 19 instructions per pixel. With a 33 MHz memory bus and the DRAM of the day, you're looking at about 5 clocks for memory latency. That looks like an upper bound of no more than 4 memory operations per pixel.
A convincing 3d renderer averaging 19 instructions and 4 memory operations per pixel. And we're not even counting blit/video delays here. Good lord is that savage optimization work. Carmack is famous for a reason.
P.S. The really scary thought is that Doom would hypothetically run on any 386 machine -- can you imagine painting e.g. 160x120 on a cacheless 20 MHz 386 laptop?
Good points regardless though.
Your point still stands, just pointing out that the target area for rendering was often smaller than 320x240.
I also remember a couple of other people that had "486" upgrades for their 386 based systems and Doom was perfectly playable on those systems as well. RAM was the big limiting factor that I remember.
On the other side, Win 3.1 was also capable of swapping and ran Doom. It was absolutely unplayable though :)
Ultima VII required a 33MHz 386DX w/ 4Mb of ram, and my computer ran it fine with a boot disk. If memory serves (and I was 7 at the time, so it probably doesn't), a DOS 6.22 bootdisk contained fields for page size, which leads me to believe it had support for virtual memory. That said, I do remember the massive stink that was made about virtual memory when Windows 95 came out, so I could be wrong.
I'm highly tempted to break out that old box and play around with it. This conversation tickles my nostalgia bone.
I also, amazingly, remember running some early version of Pagemaker on that machine. When I went to link text, I would click the mouse to start the process, go get a sandwich, watch some TV and come back 10 minutes later when it finished.
There are basically two inner loop types in a game like Doom - the wall loop and the floor loop. The wall loop renders a vertical strip of pixels on a wall and the floor loop renders a horizontal strip of floor. Each of these loops is actually rather trivial to write and just walks over the pixels reading an input texel, modulate by lighting, and then write out to the screen buffer. (Actually, Doom had transparent textures for some walls, so that's a third type of loop). The wall loop is slightly simpler because it can be an axis aligned walk through the input texture.
There really isn't very much room to optimize these loops. You can unroll them. You can play with how you do the adds and carrys and maybe shave off another instruction. For walls, you can organize your texture data so that vertical neighbors are consecutive in memory. You can be very choosy about your lighting function. The hard work was setting everything up for your inner loop.
---
286: protected memory extensions for x86
386: useful protected memory extensions for x86. (Hardly anything used 286 protected memory.)
486: first RISC-like pipelined x86
586: first superscalar x86
I'm not 100% certain, but I think the pipelining would allow you to execute (some) register-only instructions in the x86 equivalent of a delay slot.
I used to play Doom with a AMD386sx/33 with an ULSI coprocessor (a i387 clone)
====================
"Because walls were rendered as columns, wall textures were stored in memory rotated 90 degrees to the left. This was done to reduce the amount of computation required for texture coordinates"
The real reason is faster memory acces when reading linearly on old machine, less cpu cache clear. It's an old trick used on smooth rotozoomer effect in demo scene year ago.
ftp://latvia.tucows.com/pub/mirror/x2ftp/msdos/programming/demosrc/pasroto.zip
(I managed to find it back thanks to hornet.org)
Edit: you can also check out the list at ftp://latvia.tucows.com/pub/mirror/x2ftp/msdos/programming/demosrc/00index.txt
mov ax, 13h
int 10h
ah those were the days.(The DOS Doom source was never publicly released, just the Linux port, but there are remnants of some DOS code in the archive. I'm specifically looking at R_DrawSpan in README.asm and V_DrawPatchDirect in v_video.c)
(now, of course, mainly to be read for nostalgic reasons).
History is useful. We're not at the point where we want CS students to memorize what happened at the Battle of Algol in 1968, but it's darned close.