Building a Software Rasterizer on Old Hardware
While moving into a new home, I came across some old computer parts from the early 2000s and decided to put them back together. The system consists of a 1.1 GHz Athlon, 256 MB of RAM, and an ATI Radeon 9500. In 2002, this was the best machine I could afford, and apparently I decided it was worth keeping around.
I've long been fascinated by the engineering that went into software rasterizers in the mid-to-late 1990s, so I thought, "Let's give it a go on this single-core, single-threaded machine."
I went ahead and rebuilt a very stripped-back version of Arnold Console, my hand-made GUI framework, in C99. I designed it to run on both modern systems and older 32-bit machines with minimal compiler-specific adjustments.
I added the ability to load OBJ files along with a translation manipulator that allows users to select and move various elements of an object. It took some time to get the projection math for the translation manipulator working the way I wanted, but the controls now feel fairly intuitive.
Running the application under Windows 2000 and seeing how it performs there has been surprisingly delightful. The machine struggles with complex geometry containing thousands of vertices, but it was still incredibly satisfying to load and manipulate objects on hardware of that era.
Seeing how constrained developers were by the technology of the time gives me a much greater appreciation for the engineering and optimization work that was required on hardware like this. Today, it's easy to open a web browser, navigate to what appears to be a relatively simple website, and watch it consume gigabytes of memory. For development expediency and ease, we've accepted that as normal at the cost of efficiency.
Experiencing these older limitations firsthand makes it easier to understand the mindset that produced so many impressive software and game engines during the 1990s and early 2000s. When memory, CPU cycles, and storage bandwidth were genuinely scarce resources, developers had little choice but to think carefully about efficiency. Every allocation, every draw call, and every unnecessary calculation mattered.
Modern hardware has enabled incredible advances in software, and many of today's applications solve problems that would have been unimaginably slow on machines like this. At the same time, working with older constraints serves as a useful reminder that performance is often the result of discipline as much as hardware capability.
Can't we be developing things with efficiency and prudence in mind?
Especially with the availability of LLMs and modern development tools, it seems reasonable to ask whether we can build software with both speed and efficiency in mind.