2025-10-14 19:45:37
諏訪子
gamedev
graphics
vulkan

【Vulkan】Overview of the Graphics Pipeline

Lately, I've been writing a lot about assembly.
This is because it's a lot of fun.
But this time, let's take a break and discuss graphics programming.
This article focuses on theory, specifically explaining the graphics pipeline.

What is the Graphics Pipeline?

The graphics pipeline is the process by which the GPU handles graphics, resulting in what you see on the screen.
The following graphic shows each step the GPU goes through before displaying the final result on the screen:
Vulkan pipeline

It starts by obtaining vertices through code.
This can be done in languages like C or C++, but it's far more common to use model files such as .obj, .fbx, or .glb.
These vertices come from vertex buffers and index buffers and pass through the input assembler.
This is a fixed function.

The input assembler takes a list of numbers as input and groups them into geometry.
In 3D modeling programs, quadrilaterals (quads) are commonly used.
This is because they are easier for humans to work with, make animation and texturing simpler, and look cleaner.
However, computers use triangles, with one quad equating to two triangles.

Next, the vertex shader processes each vertex individually, performing transformations like rotation or translation.
The tessellation shader subdivides geometry based on specific rules, improving the quality of the mesh.
This makes flat objects that are close up appear more realistic.
This is entirely optional.

The geometry shader runs for each primitive (triangle, line, point, etc.) and can discard it or output more primitives than were input.
In a way, it's similar to the tessellation shader but far more flexible.
However, it's extremely demanding for most graphics cards, so it's rarely used today.
Like the tessellation shader, this is entirely optional.

In the rasterization stage, the geometry is divided into fragments for each pixel where triangles overlap.

The fragment shader processes each fragment individually, using interpolated data like textures, normals, and lighting to generate values such as color.

Finally, the color blending stage applies operations to mix values from multiple fragments corresponding to the same pixel.
Once all this is complete, the image is displayed in the framebuffer, which is what you see on the screen.

Types of Functions

There are two types of functions:

  • Fixed functions (marked in green).
  • Programmable stages (marked in purple).

Programmers have less control over operations in fixed function stages.
Each stage can be configured by setting variables that modify its behavior.
The input assembler, rasterization, and color blending are all fixed functions.

In programmable stages, you have the ability to upload custom code that runs on the GPU.
These small programs that run on the GPU are called shaders and are written in a language similar to C.
There are many different shader languages, such as GLSL, HLSL, MSL, and Slang.
For simplicity, let's stick with GLSL.
If you're using DirectX or an engine like Unity or Unreal (which you're probably not if you're reading this), you'll end up using HLSL, which is similar to C++ or C#.

Compute Shaders

If you've read the GLSL tutorial series, you'll know there's another type of shader called a compute shader.
However, these are not part of the graphics pipeline and are not used for graphics rendering.

Why Not Render on the CPU?

Technically, it's possible to render on the CPU, but it's extremely slow.
A CPU can only process one vertex at a time, whereas a GPU can process thousands of vertices in parallel.
However, there's a catch.
When writing programs for the GPU, what you can do is significantly limited.
You can't write GPU code the same way you would for a CPU.
This is because the hardware is fundamentally different.
Therefore, you need to work within the predefined framework of the graphics pipeline.

That's all