Building a Renderer with Metal (Part 1)
By: Kemal Enver
Tags: Metal, Programming, Rendering, Game Engine, Graphics

An overview of defunct rendering techniques

My first experience with rendering was with OpenGL while I was studying at university around 2002. I had further exposure to this technology while working at a game studio, and CAD (Computer Aided Design) business.

The APIs emerging in the early ’90s were a foray into programming hardware dedicated to rendering graphics. Up to this point graphics applications did all of the drawing and necessary calculations in software that ran on general purpose CPUs.

OpenGL was one of these first APIs. It was (and still is!) a multi-platform, low-level graphics API from the Khronos group, based on a proprietary API from SGI. By using OpenGL a developer could target any graphics card with an OpenGL driver (or even perform software rendering). There were other APIs making moves around this time such as DirectX which only worked on Microsoft Windows systems (a bit like how Metal only works on Apple’s platforms today). This overview will cover the general capabilities and methods available to developers in those early days by focusing on OpenGL.

In its infancy OpenGL was built around a state machine model. As a developer you would write code that set states, drew things to the screen, and then reset states. This style of developing was called Immediate Mode and was conceptually fairly straight forward to understand.

Drawing a coloured triangle using OpenGL immediate mode. This is easy to understand but very inefficient due to having to call a function for every vertex and its attributes.

Hello Triangle - The OpenGL code above produces something similar to this. This particular triangle was rendered using Metal on an iPad.

Sending commands to the graphics card in this way is synchronous and repetitive—which has serious consequences for performance. In this environment the hardware is often idle, waiting for the application to set all the required states and send data.

To get around these limitations OpenGL required enhancing. These enhancements were collectively dubbed retained mode. It’s worth noting that retained mode is a collection of APIs rather than an official term. It’s better to think of it as ‘not immediate mode’.

One of the goals of these enhancements was to minimise the number of functions that needed to be called, and to minimise data copying. In immediate mode rendering, every vertex required a function call. For a large 3D model there may be thousands of vertices that have to be looped over, eventually becoming a serious bottleneck. Below is a brief explanation of some things that changed — don’t worry, you don’t need to understand the details, only that things evolved to solve problems as they arose.

The first enhancement to address bottlenecks was called a vertex attribute array. Instead of calling a function many times for a set of vertices, a pointer was set to a chunk of memory that held all the data. This was an improvement, but still had a drawback —the application code could change the data in the array at any time. This meant OpenGL had to keep its own copy of the data, requiring an expensive operation every draw call.

An example of setting a vertex array pointer and drawing the vertices.

The next evolution came with VBOs (vertex buffer objects). These allowed OpenGL to represent changes in data, rather than having to recopy every draw.

There have been more enhancements since, which have further resolved some of the early deficiencies.

Recent versions of OpenGL no longer support immediate mode and every enhancement since the first version has reduced inefficiency by putting more control in the hands of developers. Although a lot of things have been improved, the API has grown more complex, and harder to learn.

One of the attractive properties of a modern API like Metal is that it doesn’t carry forward all of the legacy issues that affect older APIs such as OpenGL.