From: Michel Dänzer <[email protected]>

Avoids tearing by flipping between two scanout BOs per (non-rotated) CRTC

(Cherry picked from radeon commit 43159ef400c3b18b9f4d3e6fa1c4aef2d60d38fe)

Signed-off-by: Michel Dänzer <[email protected]>
---
 src/amdgpu_drv.h      |   2 +
 src/amdgpu_kms.c      | 138 ++++++++++++++++++++++++++++++++++++++------------
 src/drmmode_display.c |  79 ++++++++++++++++-------------
 src/drmmode_display.h |   5 +-
 4 files changed, 154 insertions(+), 70 deletions(-)

diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h
index 55be626..e7bdf7f 100644
--- a/src/amdgpu_drv.h
+++ b/src/amdgpu_drv.h
@@ -143,6 +143,7 @@ typedef enum {
        OPTION_ACCEL_METHOD,
        OPTION_DRI3,
        OPTION_SHADOW_PRIMARY,
+       OPTION_TEAR_FREE,
 } AMDGPUOpts;
 
 #define AMDGPU_VSYNC_TIMEOUT   20000   /* Maximum wait for VSYNC (in usecs) */
@@ -205,6 +206,7 @@ typedef struct {
        uint_fast32_t gpu_synced;
        Bool use_glamor;
        Bool shadow_primary;
+       Bool tear_free;
 
        /* general */
        OptionInfoPtr Options;
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index 5a672c9..f6ccbd4 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -68,6 +68,7 @@ const OptionInfoRec AMDGPUOptions_KMS[] = {
        {OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
        { OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE },
        {OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE},
+       {OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE},
        {-1, NULL, OPTV_NONE, {0}, FALSE}
 };
 
@@ -222,20 +223,9 @@ amdgpu_scanout_extents_intersect(BoxPtr extents, int x, 
int y, int w, int h)
        return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
 }
 
-static void
-amdgpu_scanout_update_abort(ScrnInfoPtr scrn, void *event_data)
-{
-       xf86CrtcPtr xf86_crtc = event_data;
-       drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
-
-       drmmode_crtc->scanout_update_pending = FALSE;
-}
-
-static void
-amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
-                             void *event_data)
+static Bool
+amdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
 {
-       xf86CrtcPtr xf86_crtc = event_data;
        drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
        DamagePtr pDamage;
        RegionPtr pRegion;
@@ -244,23 +234,24 @@ amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t 
frame, uint64_t usec,
        GCPtr gc;
        BoxRec extents;
 
-       if (!drmmode_crtc->scanout.pixmap ||
-           drmmode_crtc->dpms_mode != DPMSModeOn)
-               goto out;
+       if (drmmode_crtc->dpms_mode != DPMSModeOn ||
+           !drmmode_crtc->scanout[scanout_id].pixmap)
+               return FALSE;
 
-       pDamage = drmmode_crtc->scanout_damage;
+       pDamage = drmmode_crtc->scanout[scanout_id].damage;
        if (!pDamage)
-               goto out;
+               return FALSE;
 
        pRegion = DamageRegion(pDamage);
        if (!RegionNotEmpty(pRegion))
-               goto out;
+               return FALSE;
 
-       pDraw = &drmmode_crtc->scanout.pixmap->drawable;
+       pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
        extents = *RegionExtents(pRegion);
+       RegionEmpty(pRegion);
        if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, 
xf86_crtc->y,
                                              pDraw->width, pDraw->height))
-               goto clear_damage;
+               return FALSE;
 
        pScreen = pDraw->pScreen;
        gc = GetScratchGC(pDraw->depth, pScreen);
@@ -273,16 +264,30 @@ amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t 
frame, uint64_t usec,
                             extents.x1, extents.y1);
        FreeScratchGC(gc);
 
-       amdgpu_glamor_flush(scrn);
+       amdgpu_glamor_flush(xf86_crtc->scrn);
 
-clear_damage:
-       RegionEmpty(pRegion);
+       return TRUE;
+}
+
+static void
+amdgpu_scanout_update_abort(ScrnInfoPtr scrn, void *event_data)
+{
+       xf86CrtcPtr xf86_crtc = event_data;
+       drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
 
-out:
        drmmode_crtc->scanout_update_pending = FALSE;
 }
 
 static void
+amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
+                                                         void *event_data)
+{
+       amdgpu_scanout_do_update(event_data, 0);
+
+       amdgpu_scanout_update_abort(scrn, event_data);
+}
+
+static void
 amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 {
        drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
@@ -295,11 +300,11 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
        BoxRec extents;
 
        if (drmmode_crtc->scanout_update_pending ||
-           !drmmode_crtc->scanout.pixmap ||
+           !drmmode_crtc->scanout[0].pixmap ||
            drmmode_crtc->dpms_mode != DPMSModeOn)
                return;
 
-       pDamage = drmmode_crtc->scanout_damage;
+       pDamage = drmmode_crtc->scanout[0].damage;
        if (!pDamage)
                return;
 
@@ -307,7 +312,7 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
        if (!RegionNotEmpty(pRegion))
                return;
 
-       pDraw = &drmmode_crtc->scanout.pixmap->drawable;
+       pDraw = &drmmode_crtc->scanout[0].pixmap->drawable;
        extents = *RegionExtents(pRegion);
        if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, 
xf86_crtc->y,
                                              pDraw->width, pDraw->height))
@@ -339,6 +344,61 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 
        drmmode_crtc->scanout_update_pending = TRUE;
 }
+
+static void
+amdgpu_scanout_flip_abort(ScrnInfoPtr scrn, void *event_data)
+{
+       drmmode_crtc_private_ptr drmmode_crtc = event_data;
+
+       drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+amdgpu_scanout_flip_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, 
void *event_data)
+{
+       amdgpu_scanout_flip_abort(scrn, event_data);
+}
+
+static void
+amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
+                                       xf86CrtcPtr xf86_crtc)
+{
+       drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+       ScrnInfoPtr scrn;
+       struct amdgpu_drm_queue_entry *drm_queue_entry;
+       unsigned scanout_id;
+
+       if (drmmode_crtc->scanout_update_pending)
+               return;
+
+       scanout_id = drmmode_crtc->scanout_id ^ 1;
+       if (!amdgpu_scanout_do_update(xf86_crtc, scanout_id))
+               return;
+
+       scrn = xf86_crtc->scrn;
+       drm_queue_entry = amdgpu_drm_queue_alloc(scrn, 
AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
+                                                AMDGPU_DRM_QUEUE_ID_DEFAULT,
+                                                drmmode_crtc,
+                                                amdgpu_scanout_flip_handler,
+                                                amdgpu_scanout_flip_abort);
+       if (!drm_queue_entry) {
+               xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+                          "Allocating DRM event queue entry failed.\n");
+               return;
+       }
+
+       if (drmModePageFlip(drmmode_crtc->drmmode->fd, 
drmmode_crtc->mode_crtc->crtc_id,
+                           drmmode_crtc->scanout[scanout_id].fb_id,
+                           DRM_MODE_PAGE_FLIP_EVENT, drm_queue_entry)) {
+               xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in 
%s: %s\n",
+                          __func__, strerror(errno));
+               return;
+       }
+
+       drmmode_crtc->scanout_id = scanout_id;
+       drmmode_crtc->scanout_update_pending = TRUE;
+}
+
 static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
 {
        SCREEN_PTR(arg);
@@ -349,12 +409,16 @@ static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
        (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
        pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
 
-       if (info->shadow_primary) {
+       if (info->tear_free || info->shadow_primary) {
                xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
                int c;
 
-               for (c = 0; c < xf86_config->num_crtc; c++)
-                       amdgpu_scanout_update(xf86_config->crtc[c]);
+               for (c = 0; c < xf86_config->num_crtc; c++) {
+                       if (info->tear_free)
+                               amdgpu_scanout_flip(pScreen, info, 
xf86_config->crtc[c]);
+                       else
+                               amdgpu_scanout_update(xf86_config->crtc[c]);
+               }
        }
 
        if (info->use_glamor)
@@ -681,6 +745,13 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
        }
 
        if (info->use_glamor) {
+               info->tear_free = xf86ReturnOptValBool(info->Options,
+                                                      OPTION_TEAR_FREE, FALSE);
+
+               if (info->tear_free)
+                       xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+                                  "TearFree enabled\n");
+
                info->shadow_primary =
                        xf86ReturnOptValBool(info->Options, 
OPTION_SHADOW_PRIMARY, FALSE);
 
@@ -691,11 +762,12 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
        info->allowPageFlip = xf86ReturnOptValBool(info->Options,
                                                   OPTION_PAGE_FLIP,
                                                   TRUE);
-       if (info->shadow_primary) {
+       if (info->tear_free || info->shadow_primary) {
                    xf86DrvMsg(pScrn->scrnIndex,
                               info->allowPageFlip ? X_WARNING : X_DEFAULT,
                               "KMS Pageflipping: disabled%s\n",
-                              info->allowPageFlip ? " because of 
ShadowPrimary" : "");
+                              info->allowPageFlip ?
+                              " because of ShadowPrimary/TearFree" : "");
                    info->allowPageFlip = FALSE;
        } else {
                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 79fbecf..19f0f19 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -325,6 +325,10 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
                scanout->bo = NULL;
        }
 
+       if (scanout->damage) {
+               DamageDestroy(scanout->damage);
+               scanout->damage = NULL;
+       }
 }
 
 void
@@ -338,12 +342,9 @@ drmmode_scanout_free(ScrnInfoPtr scrn)
                        xf86_config->crtc[c]->driver_private;
 
                drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
-                                            &drmmode_crtc->scanout);
-
-               if (drmmode_crtc->scanout_damage) {
-                       DamageDestroy(drmmode_crtc->scanout_damage);
-                       drmmode_crtc->scanout_damage = NULL;
-               }
+                                            &drmmode_crtc->scanout[0]);
+               drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
+                                            &drmmode_crtc->scanout[1]);
        }
 }
 
@@ -527,43 +528,51 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr 
mode,
                        x = drmmode_crtc->prime_pixmap_x;
                        y = 0;
 
-                       drmmode_crtc_scanout_destroy(drmmode, 
&drmmode_crtc->scanout);
+                       drmmode_crtc_scanout_destroy(drmmode, 
&drmmode_crtc->scanout[0]);
+                       drmmode_crtc_scanout_destroy(drmmode, 
&drmmode_crtc->scanout[1]);
                } else
 #endif
                if (drmmode_crtc->rotate.fb_id) {
                        fb_id = drmmode_crtc->rotate.fb_id;
                        x = y = 0;
 
-                       drmmode_crtc_scanout_destroy(drmmode, 
&drmmode_crtc->scanout);
-               } else if (info->shadow_primary) {
-                       drmmode_crtc_scanout_create(crtc,
-                                                   &drmmode_crtc->scanout,
-                                                   NULL, mode->HDisplay,
-                                                   mode->VDisplay);
-
-                       if (drmmode_crtc->scanout.pixmap) {
-                               RegionPtr pRegion;
-                               BoxPtr pBox;
-
-                               if (!drmmode_crtc->scanout_damage) {
-                                       drmmode_crtc->scanout_damage =
-                                               
DamageCreate(amdgpu_screen_damage_report,
-                                                            NULL, 
DamageReportRawRegion,
-                                                            TRUE, pScreen, 
NULL);
-                                       
DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
-                                                      
drmmode_crtc->scanout_damage);
-                               }
+                       drmmode_crtc_scanout_destroy(drmmode, 
&drmmode_crtc->scanout[0]);
+                       drmmode_crtc_scanout_destroy(drmmode, 
&drmmode_crtc->scanout[1]);
+               } else if (info->tear_free || info->shadow_primary) {
+                       for (i = 0; i < (info->tear_free ? 2 : 1); i++) {
+                               drmmode_crtc_scanout_create(crtc,
+                                                           
&drmmode_crtc->scanout[i],
+                                                           NULL, 
mode->HDisplay,
+                                                           mode->VDisplay);
+
+                               if (drmmode_crtc->scanout[i].pixmap) {
+                                       RegionPtr pRegion;
+                                       BoxPtr pBox;
+
+                                       if (!drmmode_crtc->scanout[i].damage) {
+                                               drmmode_crtc->scanout[i].damage 
=
+                                                       
DamageCreate(amdgpu_screen_damage_report,
+                                                                    NULL, 
DamageReportRawRegion,
+                                                                    TRUE, 
pScreen, NULL);
+                                               
DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
+                                                              
drmmode_crtc->scanout[i].damage);
+                                       }
 
-                               pRegion = 
DamageRegion(drmmode_crtc->scanout_damage);
-                               RegionUninit(pRegion);
-                               pRegion->data = NULL;
-                               pBox = RegionExtents(pRegion);
-                               pBox->x1 = min(pBox->x1, x);
-                               pBox->y1 = min(pBox->y1, y);
-                               pBox->x2 = max(pBox->x2, x + mode->HDisplay);
-                               pBox->y2 = max(pBox->y2, y + mode->VDisplay);
+                                       pRegion = 
DamageRegion(drmmode_crtc->scanout[i].damage);
+                                       RegionUninit(pRegion);
+                                       pRegion->data = NULL;
+                                       pBox = RegionExtents(pRegion);
+                                       pBox->x1 = min(pBox->x1, x);
+                                       pBox->y1 = min(pBox->y1, y);
+                                       pBox->x2 = max(pBox->x2, x + 
mode->HDisplay);
+                                       pBox->y2 = max(pBox->y2, y + 
mode->VDisplay);
+                               }
+                       }
 
-                               fb_id = drmmode_crtc->scanout.fb_id;
+                       if (drmmode_crtc->scanout[0].pixmap &&
+                           (!info->tear_free || 
drmmode_crtc->scanout[1].pixmap)) {
+                               drmmode_crtc->scanout_id = 0;
+                               fb_id = drmmode_crtc->scanout[0].fb_id;
                                x = y = 0;
                        }
                }
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 0ba358e..8262e05 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -73,6 +73,7 @@ typedef struct {
 struct drmmode_scanout {
        struct amdgpu_buffer *bo;
        PixmapPtr pixmap;
+       DamagePtr damage;
        unsigned fb_id;
        int width, height;
 };
@@ -83,8 +84,8 @@ typedef struct {
        int hw_id;
        struct amdgpu_buffer *cursor_buffer;
        struct drmmode_scanout rotate;
-       struct drmmode_scanout scanout;
-       DamagePtr scanout_damage;
+       struct drmmode_scanout scanout[2];
+       unsigned scanout_id;
        Bool scanout_update_pending;
        int dpms_mode;
        CARD64 dpms_last_ust;
-- 
2.1.4

_______________________________________________
xorg-driver-ati mailing list
[email protected]
http://lists.x.org/mailman/listinfo/xorg-driver-ati

Reply via email to