From ae8a13cd6c0c22298cdf4b992cb8dacaeb5cf073 Mon Sep 17 00:00:00 2001
From: Laszlo Agocs <laszlo.agocs@qt.io>
Date: Wed, 2 Aug 2017 16:39:48 +0200
Subject: [PATCH 1/3] eglfs_kms: Add support for formats other than XRGB8888

Switch to drmModeAddFB2 and add mappings for RGB565 and ARGB8888,
and some BGR variants.

The default is XRGB8888, like before.

Others can be requested in the config file with
"format": "rgb565" or "argb8888" etc. on a per-output basis.

If the primary plane does not support the format, modesetting
and flipping will fail.

Task-number: QTBUG-62262
Change-Id: I8537cbeed7f046c46aa63fcea6d6946c0e0038a7
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Signed-off-by: Madhurkiran Harikrishnan <madhurkiran.harikrishnan@xilinx.com>
Upstream-Status: Backport
---
 src/platformsupport/kmsconvenience/qkmsdevice.cpp  | 35 ++++++++++++++++++++--
 src/platformsupport/kmsconvenience/qkmsdevice_p.h  |  2 ++
 .../eglfs_kms/qeglfskmsgbmscreen.cpp               | 30 ++++++++++++++-----
 .../eglfs_kms_support/qeglfskmsscreen.cpp          | 22 ++++++++++++--
 4 files changed, 77 insertions(+), 12 deletions(-)

diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
index a8eefe6..cdfa9cc 100644
--- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp
+++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
@@ -324,6 +324,34 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
     }
     qCDebug(qLcKmsDebug) << "Physical size is" << physSize << "mm" << "for output" << connectorName;
 
+    const QByteArray formatStr = userConnectorConfig.value(QStringLiteral("format"), QStringLiteral("xrgb8888"))
+            .toByteArray().toLower();
+    uint32_t drmFormat;
+    if (formatStr == "xrgb8888") {
+        drmFormat = DRM_FORMAT_XRGB8888;
+    } else if (formatStr == "xbgr8888") {
+        drmFormat = DRM_FORMAT_XBGR8888;
+    } else if (formatStr == "argb8888") {
+        drmFormat = DRM_FORMAT_ARGB8888;
+    } else if (formatStr == "abgr8888") {
+        drmFormat = DRM_FORMAT_ABGR8888;
+    } else if (formatStr == "rgb565") {
+        drmFormat = DRM_FORMAT_RGB565;
+    } else if (formatStr == "bgr565") {
+        drmFormat = DRM_FORMAT_BGR565;
+    } else if (formatStr == "xrgb2101010") {
+        drmFormat = DRM_FORMAT_XRGB2101010;
+    } else if (formatStr == "xbgr2101010") {
+        drmFormat = DRM_FORMAT_XBGR2101010;
+    } else if (formatStr == "argb2101010") {
+        drmFormat = DRM_FORMAT_ARGB2101010;
+    } else if (formatStr == "abgr2101010") {
+        drmFormat = DRM_FORMAT_ABGR2101010;
+    } else {
+        qWarning("Invalid pixel format \"%s\" for output %s", formatStr.constData(), connectorName.constData());
+        drmFormat = DRM_FORMAT_XRGB8888;
+    }
+
     QKmsOutput output = {
         QString::fromUtf8(connectorName),
         connector->connector_id,
@@ -335,9 +363,10 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
         modes,
         connector->subpixel,
         connectorProperty(connector, QByteArrayLiteral("DPMS")),
-        false,
-        0,
-        false
+        false, // wants_plane
+        0, // plane_id
+        false, // plane_set
+        drmFormat
     };
 
     bool ok;
diff --git a/src/platformsupport/kmsconvenience/qkmsdevice_p.h b/src/platformsupport/kmsconvenience/qkmsdevice_p.h
index 35a51c1..beb4c49 100644
--- a/src/platformsupport/kmsconvenience/qkmsdevice_p.h
+++ b/src/platformsupport/kmsconvenience/qkmsdevice_p.h
@@ -59,6 +59,7 @@
 
 #include <xf86drm.h>
 #include <xf86drmMode.h>
+#include <drm_fourcc.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -109,6 +110,7 @@ struct QKmsOutput
     bool wants_plane;
     uint32_t plane_id;
     bool plane_set;
+    uint32_t drm_format;
 
     void restoreMode(QKmsDevice *device);
     void cleanup(QKmsDevice *device);
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index 87fb314..9ea5cce 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -55,6 +55,18 @@ QT_BEGIN_NAMESPACE
 
 Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
 
+static inline uint32_t drmFormatToGbmFormat(uint32_t drmFormat)
+{
+    Q_ASSERT(DRM_FORMAT_XRGB8888 == GBM_FORMAT_XRGB8888);
+    return drmFormat;
+}
+
+static inline uint32_t gbmFormatToDrmFormat(uint32_t gbmFormat)
+{
+    Q_ASSERT(DRM_FORMAT_XRGB8888 == GBM_FORMAT_XRGB8888);
+    return gbmFormat;
+}
+
 void QEglFSKmsGbmScreen::bufferDestroyedHandler(gbm_bo *bo, void *data)
 {
     FrameBuffer *fb = static_cast<FrameBuffer *>(data);
@@ -77,13 +89,16 @@ QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject(
 
     uint32_t width = gbm_bo_get_width(bo);
     uint32_t height = gbm_bo_get_height(bo);
-    uint32_t stride = gbm_bo_get_stride(bo);
-    uint32_t handle = gbm_bo_get_handle(bo).u32;
+    uint32_t handles[4] = { gbm_bo_get_handle(bo).u32 };
+    uint32_t strides[4] = { gbm_bo_get_stride(bo) };
+    uint32_t offsets[4] = { 0 };
+    uint32_t pixelFormat = gbmFormatToDrmFormat(gbm_bo_get_format(bo));
 
     QScopedPointer<FrameBuffer> fb(new FrameBuffer);
+    qCDebug(qLcEglfsKmsDebug, "Adding FB, size %ux%u, DRM format 0x%x", width, height, pixelFormat);
 
-    int ret = drmModeAddFB(device()->fd(), width, height, 24, 32,
-                           stride, handle, &fb->fb);
+    int ret = drmModeAddFB2(device()->fd(), width, height, pixelFormat,
+                            handles, strides, offsets, &fb->fb, 0);
 
     if (ret) {
         qWarning("Failed to create KMS FB!");
@@ -132,11 +147,12 @@ QPlatformCursor *QEglFSKmsGbmScreen::cursor() const
 gbm_surface *QEglFSKmsGbmScreen::createSurface()
 {
     if (!m_gbm_surface) {
-        qCDebug(qLcEglfsKmsDebug) << "Creating window for screen" << name();
+        uint32_t gbmFormat = drmFormatToGbmFormat(m_output.drm_format);
+        qCDebug(qLcEglfsKmsDebug, "Creating gbm_surface for screen %s with format 0x%x", qPrintable(name()), gbmFormat);
         m_gbm_surface = gbm_surface_create(static_cast<QEglFSKmsGbmDevice *>(device())->gbmDevice(),
                                            rawGeometry().width(),
                                            rawGeometry().height(),
-                                           GBM_FORMAT_XRGB8888,
+                                           gbmFormat,
                                            GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
     }
     return m_gbm_surface;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
index 3951f46..7007709 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
@@ -101,12 +101,30 @@ QRect QEglFSKmsScreen::rawGeometry() const
 
 int QEglFSKmsScreen::depth() const
 {
-    return 32;
+    return format() == QImage::Format_RGB16 ? 16 : 32;
 }
 
 QImage::Format QEglFSKmsScreen::format() const
 {
-    return QImage::Format_RGB32;
+    // the result can be slightly incorrect, it won't matter in practice
+    switch (m_output.drm_format) {
+    case DRM_FORMAT_ARGB8888:
+    case DRM_FORMAT_ABGR8888:
+        return QImage::Format_ARGB32;
+    case DRM_FORMAT_RGB565:
+    case DRM_FORMAT_BGR565:
+        return QImage::Format_RGB16;
+    case DRM_FORMAT_XRGB2101010:
+        return QImage::Format_RGB30;
+    case DRM_FORMAT_XBGR2101010:
+        return QImage::Format_BGR30;
+    case DRM_FORMAT_ARGB2101010:
+        return QImage::Format_A2RGB30_Premultiplied;
+    case DRM_FORMAT_ABGR2101010:
+        return QImage::Format_A2BGR30_Premultiplied;
+    default:
+        return QImage::Format_RGB32;
+    }
 }
 
 QSizeF QEglFSKmsScreen::physicalSize() const
-- 
2.7.4

