Introduction to Vulkan Compute¶
What is Vulkan?¶
Vulkan is a modern, low-level graphics and compute API developed by the Khronos Group. Unlike higher-level APIs such as OpenGL or CUDA, which manage much of the GPU state for you, Vulkan gives you explicit control over the GPU, resulting in better performance but requiring more code.
Graphics vs Compute¶
Vulkan supports two main types of workloads:
| Aspect | Graphics | Compute |
|---|---|---|
| Purpose | Rendering images | General-purpose processing |
| Pipeline | Complex (vertex, fragment, etc.) | Simple (single stage) |
| Output | Framebuffer/images | Buffers/images |
| Use cases | Games, visualization | ML, physics, image processing |
This series focuses entirely on Compute — using the GPU as a massively parallel processor.
The Vulkan Execution Model¶
1. Host and Device¶
flowchart TB
subgraph HOST["HOST (CPU)"]
direction LR
App["Application<br/>(Your C)"] --> Lib["Vulkan<br/>Library"] --> Drv["Driver"]
end
subgraph DEVICE["DEVICE (GPU)"]
direction TB
subgraph CUs["Compute Units"]
direction LR
CU1["CU"]
CU2["CU"]
CU3["CU"]
CU4["CU"]
CU5["..."]
end
MEM["GPU Memory"]
end
HOST --> DEVICE
- Host: Your CPU and system memory where your C code runs
- Device: The GPU with its own memory and compute units
2. Queues and Commands¶
The GPU doesn't execute code directly. Instead, you:
- Record commands into a command buffer
- Submit the command buffer to a queue
- The GPU processes commands asynchronously
// Record commands
vkBeginCommandBuffer(cmd, &begin_info);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
vkCmdDispatch(cmd, group_count_x, 1, 1);
vkEndCommandBuffer(cmd);
// Submit to queue
vkQueueSubmit(queue, 1, &submit_info, fence);
// Wait for completion
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
3. Workgroups and Invocations¶
Compute shaders run in a hierarchical structure. Dispatches, workgroups, and
invocations each have 3D coordinates (x, y, z) — this series only ever uses
the x dimension, so you'll see indices like (1,0,0) and gl_GlobalInvocationID.x
throughout:
flowchart TD
D["Dispatch (vkCmdDispatch)"]
D --> WG0["Workgroup [0,0,0]"]
D --> WG1["Workgroup [1,0,0]"]
D --> WGN["Workgroup [N,0,0]"]
WG0 --> I0["Invocation (0,0,0)"]
WG0 --> I1["Invocation (1,0,0)"]
WG0 --> I2["Invocation (2,0,0)"]
WG0 --> I3["... up to local_size"]
- Invocation: A single execution of your shader (like a thread)
- Workgroup: A group of invocations that can share memory and synchronize
- Dispatch: The total number of workgroups to launch
Compute Shaders (GLSL)¶
Shaders are written in GLSL and compiled to SPIR-V:
#version 450
// Workgroup size: 256 threads
layout(local_size_x = 256) in;
// Input/output buffers
layout(set = 0, binding = 0) readonly buffer Input {
float data[];
} input_buf;
layout(set = 0, binding = 1) writeonly buffer Output {
float data[];
} output_buf;
void main() {
uint idx = gl_GlobalInvocationID.x;
output_buf.data[idx] = input_buf.data[idx] * 2.0;
}
Key concepts:
local_size_x: Threads per workgroupgl_GlobalInvocationID: Unique index for this invocationlayout(set, binding): Where to find resources
The Vulkan Workflow¶
Every Vulkan compute program follows this pattern:
flowchart TD
A["1. Initialize<br/>Create instance, device, queue"]
B["2. Setup Resources<br/>Allocate buffers · Create descriptor sets · Load/create pipeline"]
C["3. Execute<br/>Record command buffer · Submit to queue · Wait for completion"]
D["4. Cleanup<br/>Destroy all objects"]
A --> B --> C --> D
Error Handling¶
Vulkan functions return VkResult. Always check for success:
VkResult result = vkCreateBuffer(device, &info, NULL, &buffer);
if (result != VK_SUCCESS) {
fprintf(stderr, "Failed to create buffer: %d\n", result);
return -1;
}
Validation Layers¶
Vulkan has minimal error checking by default for performance. Enable validation layers during development:
const char* layers[] = {"VK_LAYER_KHRONOS_validation"};
VkInstanceCreateInfo create_info = {
// ...
.enabledLayerCount = 1,
.ppEnabledLayerNames = layers
};
Validation layers catch:
- Invalid API usage
- Memory leaks
- Synchronization errors
- Best practice violations
What's Next?¶
Now that you understand the concepts, let's write code! Head to Chapter 01 to create your first Vulkan program.
Don't worry
Vulkan has a lot of concepts, but you'll learn them incrementally. Each chapter introduces just a few new ideas, building on what you've already learned.