Skip to content

Instantly share code, notes, and snippets.

@leonkasovan
Forked from varphone/drm-gbm.c
Created January 19, 2024 08:19
Show Gist options
  • Save leonkasovan/2e76ccac79136cf6fb36b86be932aec1 to your computer and use it in GitHub Desktop.
Save leonkasovan/2e76ccac79136cf6fb36b86be932aec1 to your computer and use it in GitHub Desktop.
drm-gbm
// gcc -o drm-gbm drm-gbm.c -ldrm -lgbm -lEGL -lGL -I/usr/include/libdrm
// general documentation: man drm
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define EXIT(msg) { fputs (msg, stderr); exit (EXIT_FAILURE); }
static int device;
static drmModeConnector *find_connector (drmModeRes *resources) {
// iterate the connectors
int i;
for (i=0; i<resources->count_connectors; i++) {
drmModeConnector *connector = drmModeGetConnector (device, resources->connectors[i]);
// pick the first connected connector
if (connector->connection == DRM_MODE_CONNECTED) {
return connector;
}
drmModeFreeConnector (connector);
}
// no connector found
return NULL;
}
static drmModeEncoder *find_encoder (drmModeRes *resources, drmModeConnector *connector) {
if (connector->encoder_id) {
return drmModeGetEncoder (device, connector->encoder_id);
}
// no encoder found
return NULL;
}
static uint32_t connector_id;
static drmModeModeInfo mode_info;
static drmModeCrtc *crtc;
static void find_display_configuration () {
drmModeRes *resources = drmModeGetResources (device);
// find a connector
drmModeConnector *connector = find_connector (resources);
if (!connector) EXIT ("no connector found\n");
// save the connector_id
connector_id = connector->connector_id;
// save the first mode
mode_info = connector->modes[0];
printf ("resolution: %ix%i\n", mode_info.hdisplay, mode_info.vdisplay);
// find an encoder
drmModeEncoder *encoder = find_encoder (resources, connector);
if (!encoder) EXIT ("no encoder found\n");
// find a CRTC
if (encoder->crtc_id) {
crtc = drmModeGetCrtc (device, encoder->crtc_id);
}
drmModeFreeEncoder (encoder);
drmModeFreeConnector (connector);
drmModeFreeResources (resources);
}
static struct gbm_device *gbm_device;
static EGLDisplay display;
static EGLContext context;
static struct gbm_surface *gbm_surface;
static EGLSurface egl_surface;
//#define trace() printf("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
#define trace()
static void setup_opengl () {
gbm_device = gbm_create_device (device);
trace();
display = eglGetDisplay (gbm_device);
trace();
eglInitialize (display, NULL, NULL);
trace();
// create an OpenGL context
eglBindAPI (EGL_OPENGL_API);
trace();
EGLint attributes[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_NONE};
EGLConfig config;
EGLint num_config;
eglChooseConfig (display, attributes, &config, 1, &num_config);
trace();
context = eglCreateContext (display, config, EGL_NO_CONTEXT, NULL);
trace();
// create the GBM and EGL surface
gbm_surface = gbm_surface_create (gbm_device, mode_info.hdisplay, mode_info.vdisplay, GBM_BO_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT|GBM_BO_USE_RENDERING);
trace();
egl_surface = eglCreateWindowSurface (display, config, gbm_surface, NULL);
trace();
eglMakeCurrent (display, egl_surface, egl_surface, context);
trace();
}
static struct gbm_bo *previous_bo = NULL;
static uint32_t previous_fb;
static void swap_buffers () {
eglSwapBuffers (display, egl_surface);
struct gbm_bo *bo = gbm_surface_lock_front_buffer (gbm_surface);
uint32_t handle = gbm_bo_get_handle (bo).u32;
uint32_t pitch = gbm_bo_get_stride (bo);
uint32_t fb;
drmModeAddFB (device, mode_info.hdisplay, mode_info.vdisplay, 24, 32, pitch, handle, &fb);
trace();
drmModeSetCrtc (device, crtc->crtc_id, fb, 0, 0, &connector_id, 1, &mode_info);
trace();
if (previous_bo) {
drmModeRmFB (device, previous_fb);
trace();
gbm_surface_release_buffer (gbm_surface, previous_bo);
trace();
}
previous_bo = bo;
previous_fb = fb;
trace();
}
static void draw (float progress) {
trace();
glClearColor (1.0f-progress, progress, 0.0, 1.0);
glClear (GL_COLOR_BUFFER_BIT);
trace();
swap_buffers ();
trace();
}
static void clean_up () {
// set the previous crtc
drmModeSetCrtc (device, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, &connector_id, 1, &crtc->mode);
trace();
drmModeFreeCrtc (crtc);
trace();
if (previous_bo) {
drmModeRmFB (device, previous_fb);
trace();
gbm_surface_release_buffer (gbm_surface, previous_bo);
trace();
}
trace();
eglDestroySurface (display, egl_surface);
trace();
gbm_surface_destroy (gbm_surface);
trace();
eglDestroyContext (display, context);
trace();
eglTerminate (display);
trace();
gbm_device_destroy (gbm_device);
}
int main () {
device = open ("/dev/dri/card0", O_RDWR|O_CLOEXEC);
find_display_configuration ();
setup_opengl ();
int i;
for (i = 0; i < 600; i++)
draw (i / 600.0f);
clean_up ();
close (device);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment