SDL: fix: Use drmModeAddFB2WithModifiers instead of drmModeAddFB to allow using GBM modifiers.

From 620e875335e35a6cc6c187079951f598bfd3b595 Mon Sep 17 00:00:00 2001
From: Cecill Etheredge <[EMAIL REDACTED]>
Date: Tue, 25 Jun 2024 22:43:32 +0200
Subject: [PATCH] fix: Use drmModeAddFB2WithModifiers instead of drmModeAddFB
 to allow using GBM modifiers.

This fixes corrupt framebuffers on platforms that require the use of modifiers.
---
 src/video/kmsdrm/SDL_kmsdrmsym.h   |  9 +++++++++
 src/video/kmsdrm/SDL_kmsdrmvideo.c | 32 +++++++++++++++++++++---------
 2 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/src/video/kmsdrm/SDL_kmsdrmsym.h b/src/video/kmsdrm/SDL_kmsdrmsym.h
index d1e856f4b77ce..49680448984c1 100644
--- a/src/video/kmsdrm/SDL_kmsdrmsym.h
+++ b/src/video/kmsdrm/SDL_kmsdrmsym.h
@@ -54,6 +54,11 @@ SDL_KMSDRM_SYM(int,drmModeAddFB2,(int fd, uint32_t width, uint32_t height,
                          const uint32_t pitches[4], const uint32_t offsets[4],
                          uint32_t *buf_id, uint32_t flags))
 
+SDL_KMSDRM_SYM(int,drmModeAddFB2WithModifiers,(int fd, uint32_t width,
+                         uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4],
+                         const uint32_t pitches[4], const uint32_t offsets[4],
+                         const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags))
+
 SDL_KMSDRM_SYM(int,drmModeRmFB,(int fd, uint32_t bufferId))
 SDL_KMSDRM_SYM(drmModeFBPtr,drmModeGetFB,(int fd, uint32_t buf))
 SDL_KMSDRM_SYM(drmModeCrtcPtr,drmModeGetCrtc,(int fd, uint32_t crtcId))
@@ -124,6 +129,10 @@ SDL_KMSDRM_SYM(void,gbm_surface_destroy,(struct gbm_surface *surf))
 SDL_KMSDRM_SYM(struct gbm_bo *,gbm_surface_lock_front_buffer,(struct gbm_surface *surf))
 SDL_KMSDRM_SYM(void,gbm_surface_release_buffer,(struct gbm_surface *surf, struct gbm_bo *bo))
 
+SDL_KMSDRM_SYM(uint64_t,gbm_bo_get_modifier,(struct gbm_bo *bo))
+SDL_KMSDRM_SYM(int,gbm_bo_get_plane_count,(struct gbm_bo *bo))
+SDL_KMSDRM_SYM(uint32_t,gbm_bo_get_offset,(struct gbm_bo *bo, int plane))
+SDL_KMSDRM_SYM(uint32_t,gbm_bo_get_stride_for_plane,(struct gbm_bo *bo, int plane))
 
 #undef SDL_KMSDRM_MODULE
 #undef SDL_KMSDRM_SYM
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c
index bdcd2207adea6..2dab65cbccc0e 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -336,8 +336,9 @@ KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo)
 {
     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
     unsigned w, h;
-    int ret;
-    Uint32 stride, handle;
+    int ret, num_planes = 0;
+    Uint32 format, strides[4] = { 0 }, handles[4] = { 0 }, offsets[4] = { 0 }, flags = 0;
+    uint64_t modifiers[4] = { 0 };
 
     /* Check for an existing framebuffer */
     KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)KMSDRM_gbm_bo_get_user_data(bo);
@@ -357,20 +358,33 @@ KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo)
 
     fb_info->drm_fd = viddata->drm_fd;
 
-    /* Create framebuffer object for the buffer */
+    /* Create framebuffer object for the buffer using the modifiers requested by GBM.
+       Use of the modifiers is necessary on some platforms. */
     w = KMSDRM_gbm_bo_get_width(bo);
     h = KMSDRM_gbm_bo_get_height(bo);
-    stride = KMSDRM_gbm_bo_get_stride(bo);
-    handle = KMSDRM_gbm_bo_get_handle(bo).u32;
-    ret = KMSDRM_drmModeAddFB(viddata->drm_fd, w, h, 24, 32, stride, handle,
-                              &fb_info->fb_id);
+    format = KMSDRM_gbm_bo_get_format(bo);
+
+    modifiers[0] = KMSDRM_gbm_bo_get_modifier(bo);
+    num_planes = KMSDRM_gbm_bo_get_plane_count(bo);
+    for (int i = 0; i < num_planes; i++) {
+        strides[i] = KMSDRM_gbm_bo_get_stride_for_plane(bo, i);
+        handles[i] = KMSDRM_gbm_bo_get_handle(bo).u32;
+        offsets[i] = KMSDRM_gbm_bo_get_offset(bo, i);
+        modifiers[i] = modifiers[0];
+    }
+
+    if (modifiers[0]) {
+        flags = DRM_MODE_FB_MODIFIERS;
+    }
+
+    ret = KMSDRM_drmModeAddFB2WithModifiers(viddata->drm_fd, w, h, format, handles, strides, offsets, modifiers, &fb_info->fb_id, flags);
     if (ret) {
         SDL_free(fb_info);
         return NULL;
     }
 
-    SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "New DRM FB (%u): %ux%u, stride %u from BO %p",
-                 fb_info->fb_id, w, h, stride, (void *)bo);
+    SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "New DRM FB (%u): %ux%u, from BO %p",
+                 fb_info->fb_id, w, h, (void *)bo);
 
     /* Associate our DRM framebuffer with this buffer object */
     KMSDRM_gbm_bo_set_user_data(bo, fb_info, KMSDRM_FBDestroyCallback);