Blob Blame History Raw
From 83b6c5e1e463f86169384a50c56fdbde1114bed5 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@gmail.com>
Date: Wed, 10 Jun 2015 13:41:02 +1000
Subject: [PATCH xserver 4/8] modesetting: reverse prime support (v1.1)

This adds support for reverse prime to the modesetting driver.

Reverse prime is where we have two GPUs in the display chain,
but the second GPU can't scanout from the shared pixmap, so needs
an extra copy to the on screen pixmap.

This allows modesetting to support this scenario while still
supporting the USB offload one.

v1.1:
fix comment + ret = bits (Eric)

Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
(cherry picked from commit 7328fb3f2b468048faf4ed4c29db720b5bf00b05)
---
 hw/xfree86/drivers/modesetting/driver.c          | 17 +++++-
 hw/xfree86/drivers/modesetting/drmmode_display.c | 74 ++++++++++++++++++++++--
 hw/xfree86/drivers/modesetting/drmmode_display.h |  4 +-
 3 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index 71a4209..088a4bc 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -580,7 +580,7 @@ msBlockHandler(ScreenPtr pScreen, void *pTimeout, void *pReadmask)
     pScreen->BlockHandler(pScreen, pTimeout, pReadmask);
     ms->BlockHandler = pScreen->BlockHandler;
     pScreen->BlockHandler = msBlockHandler;
-    if (pScreen->isGPU)
+    if (pScreen->isGPU && !ms->drmmode.reverse_prime_offload_mode)
         dispatch_slave_dirty(pScreen);
     else if (ms->dirty_enabled)
         dispatch_dirty(pScreen);
@@ -1137,10 +1137,18 @@ msSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle)
     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
     modesettingPtr ms = modesettingPTR(scrn);
     Bool ret;
-    int size = ppix->devKind * ppix->drawable.height;
     int ihandle = (int) (long) fd_handle;
 
-    ret = drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, ppix->devKind, size);
+    if (ms->drmmode.reverse_prime_offload_mode) {
+        ret = glamor_back_pixmap_from_fd(ppix, ihandle,
+                                         ppix->drawable.width,
+                                         ppix->drawable.height,
+                                         ppix->devKind, ppix->drawable.depth,
+                                         ppix->drawable.bitsPerPixel);
+    } else {
+        int size = ppix->devKind * ppix->drawable.height;
+        ret = drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, ppix->devKind, size);
+    }
     if (ret == FALSE)
         return ret;
 
@@ -1331,6 +1339,9 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv)
             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                        "Failed to initialize the Present extension.\n");
         }
+        /* enable reverse prime if we are a GPU screen, and accelerated */
+        if (pScreen->isGPU)
+            ms->drmmode.reverse_prime_offload_mode = TRUE;
     }
 #endif
 
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 7dd85c8..d824e8b 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -50,6 +50,7 @@
 
 #include "driver.h"
 
+static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
 static int
 drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
 {
@@ -341,10 +342,14 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 
         fb_id = drmmode->fb_id;
         if (crtc->randr_crtc->scanout_pixmap) {
-            msPixmapPrivPtr ppriv =
-                msGetPixmapPriv(drmmode, crtc->randr_crtc->scanout_pixmap);
-            fb_id = ppriv->fb_id;
-            x = y = 0;
+            if (!drmmode->reverse_prime_offload_mode) {
+                msPixmapPrivPtr ppriv =
+                    msGetPixmapPriv(drmmode, crtc->randr_crtc->scanout_pixmap);
+                fb_id = ppriv->fb_id;
+                x = 0;
+            } else
+                x = drmmode_crtc->prime_pixmap_x;
+            y = 0;
         }
         else if (drmmode_crtc->rotate_fb_id) {
             fb_id = drmmode_crtc->rotate_fb_id;
@@ -507,7 +512,54 @@ drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
 }
 
 static Bool
-drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
+drmmode_set_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix)
+{
+    ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
+    PixmapPtr screenpix = screen->GetScreenPixmap(screen);
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+    int c, total_width = 0, max_height = 0, this_x = 0;
+
+    if (!ppix) {
+        if (crtc->randr_crtc->scanout_pixmap)
+            PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix);
+        drmmode_crtc->prime_pixmap_x = 0;
+        return TRUE;
+    }
+    /* iterate over all the attached crtcs to work out the bounding box */
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        xf86CrtcPtr iter = xf86_config->crtc[c];
+        if (!iter->enabled && iter != crtc)
+            continue;
+        if (iter == crtc) {
+            this_x = total_width;
+            total_width += ppix->drawable.width;
+            if (max_height < ppix->drawable.height)
+                max_height = ppix->drawable.height;
+        } else {
+            total_width += iter->mode.HDisplay;
+            if (max_height < iter->mode.VDisplay)
+                max_height = iter->mode.VDisplay;
+        }
+    }
+
+    if (total_width != screenpix->drawable.width ||
+        max_height != screenpix->drawable.height) {
+
+        if (!drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height))
+            return FALSE;
+
+        screenpix = screen->GetScreenPixmap(screen);
+        screen->width = screenpix->drawable.width = total_width;
+        screen->height = screenpix->drawable.height = max_height;
+    }
+    drmmode_crtc->prime_pixmap_x = this_x;
+    PixmapStartDirtyTracking2(ppix, screenpix, 0, 0, this_x, 0);
+    return TRUE;
+}
+
+static Bool
+drmmode_set_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix)
 {
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
     drmmode_ptr drmmode = drmmode_crtc->drmmode;
@@ -548,6 +600,18 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
     return TRUE;
 }
 
+static Bool
+drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+    drmmode_ptr drmmode = drmmode_crtc->drmmode;
+
+    if (drmmode->reverse_prime_offload_mode)
+        return drmmode_set_scanout_pixmap_gpu(crtc, ppix);
+    else
+        return drmmode_set_scanout_pixmap_cpu(crtc, ppix);
+}
+
 static void *
 drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
 {
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 3a7d222..aa54bcc 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -84,6 +84,8 @@ typedef struct {
     uint32_t triple_buffer_name;
 
     DevPrivateKeyRec pixmapPrivateKeyRec;
+
+    Bool reverse_prime_offload_mode;
 } drmmode_rec, *drmmode_ptr;
 
 typedef struct {
@@ -98,7 +100,7 @@ typedef struct {
 
     drmmode_bo rotate_bo;
     unsigned rotate_fb_id;
-
+    unsigned prime_pixmap_x;
     /**
      * @{ MSC (vblank count) handling for the PRESENT extension.
      *
-- 
2.7.4