Thursday, February 26, 2026
Rendering graphics on Linux with SDL2
Simple DirectMedia Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D. It is used by video playback software, emulators, and popular games including Valve's award winning catalog and many Humble Bundle games.
SDL officially supports Windows, macOS, Linux, iOS, and Android. Support for other platforms may be found in the source code.
Developing on Ubuntu/Debian
sudo apt update
sudo apt install build-essential pkg-config
sudo apt install libsdl2-dev
## common addons
sudo apt install libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev libsdl2-net-dev
## OpenGL
sudo apt install libgl1-mesa-dev
Basic example
//main.c
#include <SDL2/SDL.h> // SDL main header (types, functions, constants)
#include <stdbool.h> // for bool, true, false
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
int main(int argc, char* argv[]) {
// Initialize SDL video subsystem. SDL_Init returns 0 on success.
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
SDL_Log("Unable to initialize SDL: %s", SDL_GetError()); // log SDL error
return 1;
}
// Create an SDL window centered on the screen with the defined size.
SDL_Window* window = SDL_CreateWindow(
"Blank SDL2 Window", // window title
SDL_WINDOWPOS_CENTERED, // x position
SDL_WINDOWPOS_CENTERED, // y position
WINDOW_WIDTH, // width
WINDOW_HEIGHT, // height
SDL_WINDOW_SHOWN // window flags (visible)
);
// Check window creation success.
if (!window) {
SDL_Log("Failed to create window: %s", SDL_GetError());
SDL_Quit(); // clean up SDL subsystems
return 1;
}
// Create a renderer for the window. -1 chooses the first available driver.
// SDL_RENDERER_ACCELERATED requests hardware acceleration.
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer) {
SDL_Log("Failed to create renderer: %s", SDL_GetError());
SDL_DestroyWindow(window); // destroy window before quitting
SDL_Quit();
return 1;
}
bool running = true; // main loop flag
SDL_Event event; // event container
// Main loop: handle events, clear and present the screen, throttle frame rate.
while (running) {
// Process all pending events.
while (SDL_PollEvent(&event)) {
// If window close or any key pressed, exit loop.
if (event.type == SDL_QUIT ||
(event.type == SDL_KEYDOWN)) {
running = false;
}
}
// Set draw color to opaque black (r,g,b,a) and clear the render target.
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
// Present the backbuffer to the screen.
SDL_RenderPresent(renderer);
// Simple frame cap: delay ~16 ms -> ~60 FPS.
SDL_Delay(16);
}
// Clean up resources in reverse creation order.
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
// Print the name of the video driver SDL used (useful for debugging).
printf("Video driver: %s\n", SDL_GetCurrentVideoDriver());
return 0;
}
Build command
gcc -o main main.c -lSDL2
Draw rectangle
// gcc -o main main.c -lSDL2
#include <SDL2/SDL.h>
#include <stdbool.h>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
// Helper function: draw a filled rectangle using top-left coordinates
void draw_rect(SDL_Renderer* renderer, SDL_Color color, int x, int y, int w, int h) {
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_Rect rect = { x, y, w, h };
SDL_RenderFillRect(renderer, &rect);
}
// Draw 1px outline + X connecting all corners
void draw_rect_outline(SDL_Renderer* renderer, SDL_Color color, int x, int y, int w, int h) {
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
// Outline: draw 4 lines (top, bottom, left, right) — 1px thick
// Top edge
SDL_RenderDrawLine(renderer, x, y, x + w - 1, y);
// Bottom edge
SDL_RenderDrawLine(renderer, x, y + h - 1, x + w - 1, y + h - 1);
// Left edge
SDL_RenderDrawLine(renderer, x, y, x, y + h - 1);
// Right edge
SDL_RenderDrawLine(renderer, x + w - 1, y, x + w - 1, y + h - 1);
// Diagonal "X": connect opposite corners
SDL_RenderDrawLine(renderer, x, y, x + w - 1, y + h - 1); // top-left to bottom-right
SDL_RenderDrawLine(renderer, x + w - 1, y, x, y + h - 1); // top-right to bottom-left
}
int main(int argc, char* argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
return 1;
}
SDL_Window* window = SDL_CreateWindow(
"Rectangle SDL2 Window",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH,
WINDOW_HEIGHT,
SDL_WINDOW_SHOWN
);
if (!window) {
SDL_Log("Failed to create window: %s", SDL_GetError());
SDL_Quit();
return 1;
}
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer) {
SDL_Log("Failed to create renderer: %s", SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
bool running = true;
SDL_Event event;
while (running) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT || event.type == SDL_KEYDOWN) {
running = false;
}
}
// Clear screen to black
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
// Example: draw a red rectangle at (100, 50) with size 200x100
SDL_Color red = {255, 0, 0, 255};
draw_rect(renderer, red, 100, 50, 200, 100);
// Example: draw a semi-transparent green square
SDL_Color green = {0, 255, 0, 128};
draw_rect(renderer, green, 300, 200, 80, 80);
SDL_RenderPresent(renderer);
SDL_Delay(16); // ~60 FPS
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}