A minimal Vulkan + GLFW application written in C23 that renders an RGB triangle.
- Full Vulkan setup written from scratch: instance, surface, device selection, swapchain, render pass, graphics pipeline, framebuffers, vertex buffers, command buffers, and presentation.
- Validation layers enabled for debugging.
- Double-buffered frame synchronization with fences and semaphores.
- Swapchain recreation on window resize and minimization (framebuffer resize).
- Mailbox present mode for low-latency presentation, throttled by a software frame limiter capping the loop at 60 FPS to avoid pegging the GPU.
- Minimal dependencies:
vulkan,glfw, andglslcfor shader compilation.
- A Vulkan-capable GPU and driver (the app also ships with a software fallback via
LD_LIBRARY_PATH=/run/opengl-driver/libon NixOS). glslcto compile the shaders.
The project uses just:
just # compile shaders and build the binary
just run # build and launch
just clean # remove the build directoryWithout just, the equivalent is:
mkdir -p build/shaders
glslc shaders/triangle.vert -o build/shaders/triangle.vert.spv
glslc shaders/triangle.frag -o build/shaders/triangle.frag.spv
gcc -std=c23 -Wall -Wextra -pedantic -Iinclude -c src/main.c -o build/main.o
gcc -std=c23 -Wall -Wextra -pedantic -Iinclude -c src/instance.c -o build/instance.o
gcc -std=c23 -Wall -Wextra -pedantic -Iinclude -c src/device.c -o build/device.o
gcc -std=c23 -Wall -Wextra -pedantic -Iinclude -c src/swapchain.c -o build/swapchain.o
gcc -std=c23 -Wall -Wextra -pedantic -Iinclude -c src/pipeline.c -o build/pipeline.o
gcc -std=c23 -Wall -Wextra -pedantic -Iinclude -c src/triangle.c -o build/triangle.o
gcc -std=c23 -Wall -Wextra -pedantic -o build/vulkRGB build/*.o -lglfw -lvulkan -ldl -lpthread -lmvulkRGB
├── justfile # build automation
├── include/
│ └── vulkRGB.h # shared types and function declarations
├── src/
│ ├── main.c # initialization, main loop, cleanup
│ ├── instance.c # Vulkan instance and validation layers
│ ├── device.c # physical/logical device and queues
│ ├── swapchain.c # swapchain, framebuffers, render pass
│ ├── pipeline.c # graphics pipeline and shader modules
│ └── triangle.c # vertex data and command buffer recording
├── shaders/
│ ├── triangle.vert # GLSL vertex shader
│ └── triangle.frag # GLSL fragment shader
└── build/ # generated artifacts (.o, .spv, binary)
On startup the window and surface are created, a suitable GPU is picked, and a logical device with dedicated graphics and present queues is built. The swapchain is sized to the window, then the render pass, graphics pipeline, framebuffers, and a vertex buffer holding three per-vertex-colored vertices are created. Each frame acquires a swapchain image, records a draw of the triangle, and submits it to the graphics queue before presenting.
The main loop asks the GPU for as much work as it can deliver (mailbox present mode), so a sleep-based limiter in app_run throttles the loop to FRAME_TARGET_FPS (60) in src/main.c. Bump that constant to allow higher frame rates or lower it to save power.
