From cc92dcd30977d8c752289e766516a242d9e652d1 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Wed, 5 Feb 2025 11:53:01 +0100 Subject: [PATCH] extend the API to export frame buffers using DRM PRIME file descriptors Export frame buffers, providing applications like those based on libegt with DRM PRIME file descriptors. Hence applications can next pass these DRM PRIME file descriptors down to libm2d, which finally use them to import the frame buffers created by libplanes so the GPU can ultimately render into these frame buffers. Signed-off-by: Cyrille Pitchen Signed-off-by: Ludovic Desroches --- include/planes/kms.h | 2 ++ include/planes/plane.h | 19 +++++++++++++++++++ src/kms-framebuffer.c | 24 ++++++++++++++++++++++++ src/p_kms.h | 1 + src/plane.c | 36 +++++++++++++++++++++++++++++++++++- 5 files changed, 81 insertions(+), 1 deletion(-) diff --git a/include/planes/kms.h b/include/planes/kms.h index 4d033b2..79ed91f 100644 --- a/include/planes/kms.h +++ b/include/planes/kms.h @@ -83,6 +83,8 @@ struct kms_framebuffer { uint32_t handle; uint32_t id; + int prime_fd; + void *ptr; }; diff --git a/include/planes/plane.h b/include/planes/plane.h index 7a086a1..5436f55 100644 --- a/include/planes/plane.h +++ b/include/planes/plane.h @@ -62,6 +62,8 @@ struct plane_data struct kms_framebuffer** fbs; /** The framebuffer. Must call plane_map() to allocate this. */ void** bufs; + /** The DRM PRIME file descriptor. Must call plane_fb_export() to set this. */ + int* prime_fds; unsigned int front_buf; /** The number of framebuffers. */ uint32_t buffer_count; @@ -376,6 +378,23 @@ int plane_fb_map(struct plane_data* plane); */ void plane_fb_unmap(struct plane_data* plane); +/** + * Export the framebuffer using a DRM PRIME file descriptor. + * + * @param plane The plane. + */ +int plane_fb_export(struct plane_data* plane); + +/** + * Opposite of plane_fb_export(). + * + * @param plane The plane. + * + * @note Like plane_fb_unmap(), plane_fb_unexport() is automatically called from + * plane_free() through plane_fb_free(). + */ +void plane_fb_unexport(struct plane_data* plane); + /** * Reallocate the framebuffer to the specified height, width, and format. * diff --git a/src/kms-framebuffer.c b/src/kms-framebuffer.c index 03d8200..8311fa7 100644 --- a/src/kms-framebuffer.c +++ b/src/kms-framebuffer.c @@ -78,6 +78,7 @@ struct kms_framebuffer *kms_framebuffer_create(struct kms_device *device, fb->width = width; fb->height = height; fb->format = format; + fb->prime_fd = -1; memset(&args, 0, sizeof(args)); args.width = width; @@ -244,3 +245,26 @@ void kms_framebuffer_unmap(struct kms_framebuffer *fb) fb->ptr = NULL; } } + +int kms_framebuffer_export(struct kms_framebuffer *fb, int *prime_fd) +{ + struct kms_device *device = fb->device; + struct drm_prime_handle args; + int err; + + if (fb->prime_fd != -1) { + *prime_fd = fb->prime_fd; + return 0; + } + + memset(&args, 0, sizeof(args)); + args.handle = fb->handle; + + err = drmIoctl(device->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); + if (err < 0) + return -errno; + + *prime_fd = fb->prime_fd = args.fd; + + return 0; +} diff --git a/src/p_kms.h b/src/p_kms.h index 65ba010..8d77c0f 100644 --- a/src/p_kms.h +++ b/src/p_kms.h @@ -57,6 +57,7 @@ struct kms_framebuffer *kms_framebuffer_create(struct kms_device *device, void kms_framebuffer_free(struct kms_framebuffer *fb); int kms_framebuffer_map(struct kms_framebuffer *fb, void **ptrp); void kms_framebuffer_unmap(struct kms_framebuffer *fb); +int kms_framebuffer_export(struct kms_framebuffer *fb, int *prime_fd); struct kms_screen *kms_screen_create(struct kms_device *device, uint32_t id); void kms_screen_free(struct kms_screen *screen); diff --git a/src/plane.c b/src/plane.c index 6fe7a2f..3cc0ca0 100644 --- a/src/plane.c +++ b/src/plane.c @@ -90,9 +90,10 @@ struct plane_data* plane_create_buffered(struct kms_device* device, int type, plane->fbs = calloc(buffer_count, sizeof(struct kms_framebuffer*)); plane->bufs = calloc(buffer_count, sizeof(void*)); + plane->prime_fds = calloc(buffer_count, sizeof(int)); plane->gem_names = calloc(buffer_count, sizeof(uint32_t*)); - if (!plane->fbs || !plane->bufs || !plane->gem_names) { + if (!plane->fbs || !plane->bufs || !plane->prime_fds || !plane->gem_names) { LOG("error: failed to allocate plane\n"); goto abort; } @@ -137,6 +138,7 @@ struct plane_data* plane_create_buffered(struct kms_device* device, int type, goto abort; } } + plane->prime_fds[fb] = -1; } plane->index = index; @@ -168,6 +170,7 @@ static void plane_fb_free(struct plane_data* plane) uint32_t fb; plane_fb_unmap(plane); + plane_fb_unexport(plane); for (fb = 0; fb < plane->buffer_count; fb++) { if (plane->fbs[fb]) { @@ -186,6 +189,8 @@ void plane_free(struct plane_data* plane) free(plane->fbs); if (plane->bufs) free(plane->bufs); + if (plane->prime_fds) + free(plane->prime_fds); if (plane->gem_names) free(plane->gem_names); free(plane); @@ -465,6 +470,35 @@ void plane_fb_unmap(struct plane_data* plane) } } +int plane_fb_export(struct plane_data* plane) +{ + uint32_t fb; + + for (fb = 0; fb < plane->buffer_count; fb++) { + if (plane->prime_fds[fb] == -1) { + int err; + + err = kms_framebuffer_export(plane->fbs[fb], &plane->prime_fds[fb]); + if (err < 0) + { + LOG("error: kms_framebuffer_export() failed: %s\n", + strerror(-err)); + return err; + } + } + } + + return 0; +} + +void plane_fb_unexport(struct plane_data* plane) +{ + uint32_t fb; + + for (fb = 0; fb < plane->buffer_count; fb++) + plane->prime_fds[fb] = -1; +} + int plane_flip(struct plane_data* plane, uint32_t target) { plane->front_buf = target;