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

From e9a93246ef0889f3f40503e9ba24b168526ae31e 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.

(cherry picked from commit 620e875335e35a6cc6c187079951f598bfd3b595)
(cherry picked from commit 6589287ed6c7701ba98efc2833b4dd9891ccece5)
---
 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 ad91d0691f758..2b4fe4bf35dc6 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))
@@ -120,6 +125,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 ccc72b6f55a37..4a873a32c4a51 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -352,8 +352,9 @@ KMSDRM_FBInfo *KMSDRM_FBFromBO(SDL_VideoDevice *_this, struct gbm_bo *bo)
 {
     SDL_VideoData *viddata = _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);
@@ -372,20 +373,33 @@ KMSDRM_FBInfo *KMSDRM_FBFromBO(SDL_VideoDevice *_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);