From: Michel Dänzer <michel.daenzer@amd.com>
Date: Mon Jul 11 12:22:09 2016 +0900
Subject: [PATCH 10/20]Use EventCallback to avoid flushing every time in the FlushCallback
Patch-mainline: Upstream
Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati
Git-commit: 9a1afbf61fbb2827c86bd86d295fa0848980d60b
References: bsc#990066
Signed-off-by: Max Staudt <mstaudt@suse.de>

We only need to flush for XDamageNotify events.

Significantly reduces compositing slowdown due to flushing overhead, in
particular with glamor.

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
---
 src/radeon.h     |  2 ++
 src/radeon_kms.c | 79 +++++++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 66 insertions(+), 15 deletions(-)

diff --git a/src/radeon.h b/src/radeon.h
index 37d5fb6..25ff61c 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -473,6 +473,8 @@ typedef struct {
     Bool              RenderAccel; /* Render */
     Bool              allowColorTiling;
     Bool              allowColorTiling2D;
+    int               callback_event_type;
+    uint_fast32_t     callback_needs_flush;
     uint_fast32_t     gpu_flushed;
     uint_fast32_t     gpu_synced;
     struct radeon_accel_state *accel_state;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index a618513..f778d30 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -51,6 +51,8 @@
 #include <X11/extensions/dpms.h>
 #endif

+#include <X11/extensions/damageproto.h>
+
 #include "radeon_chipinfo_gen.h"

 #include "radeon_bo_gem.h"
@@ -91,10 +93,11 @@ void radeon_cs_flush_indirect(ScrnInfoPtr pScrn)
     struct radeon_accel_state *accel_state;
     int ret;

+    info->gpu_flushed++;
+
 #ifdef USE_GLAMOR
     if (info->use_glamor) {
 	glamor_block_handler(pScrn->pScreen);
-	info->gpu_flushed++;
 	return;
     }
 #endif
@@ -237,8 +240,51 @@ radeonUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
     shadowUpdatePacked(pScreen, pBuf);
 }

+static Bool
+callback_needs_flush(RADEONInfoPtr info)
+{
+    return (int)(info->callback_needs_flush - info->gpu_flushed) > 0;
+}
+
+static void
+radeon_event_callback(CallbackListPtr *list,
+		      pointer user_data, pointer call_data)
+{
+    EventInfoRec *eventinfo = call_data;
+    ScrnInfoPtr pScrn = user_data;
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    int i;
+
+    if (callback_needs_flush(info))
+	return;
+
+    /* Don't let gpu_flushed get too far ahead of callback_needs_flush,
+     * in order to prevent false positives in callback_needs_flush()
+     */
+    info->callback_needs_flush = info->gpu_flushed;
+
+    for (i = 0; i < eventinfo->count; i++) {
+	if (eventinfo->events[i].u.u.type == info->callback_event_type) {
+	    info->callback_needs_flush++;
+	    return;
+	}
+    }
+}
+
+static void
+radeon_flush_callback(CallbackListPtr *list,
+		      pointer user_data, pointer call_data)
+{
+    ScrnInfoPtr pScrn = user_data;
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+
+    if (pScrn->vtSema && callback_needs_flush(info))
+        radeon_cs_flush_indirect(pScrn);
+}
+
 static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen)
 {
+    ExtensionEntry *damage_ext = CheckExtension("DAMAGE");
     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
     RADEONInfoPtr  info   = RADEONPTR(pScrn);
     PixmapPtr pixmap;
@@ -294,6 +340,19 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen)
     if (info->use_glamor)
 	radeon_glamor_create_screen_resources(pScreen);

+    info->callback_event_type = -1;
+    if (damage_ext) {
+	info->callback_event_type = damage_ext->eventBase + XDamageNotify;
+
+	if (!AddCallback(&FlushCallback, radeon_flush_callback, pScrn))
+	    return FALSE;
+
+	if (!AddCallback(&EventCallback, radeon_event_callback, pScrn)) {
+	    DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn);
+	    return FALSE;
+	}
+    }
+
     return TRUE;
 }

@@ -641,16 +700,6 @@ static void RADEONBlockHandler_oneshot(BLOCKHANDLER_ARGS_DECL)
     drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE);
 }

-static void
-radeon_flush_callback(CallbackListPtr *list,
-		      pointer user_data, pointer call_data)
-{
-    ScrnInfoPtr pScrn = user_data;
-
-    if (pScrn->vtSema)
-        radeon_cs_flush_indirect(pScrn);
-}
-
 static Bool RADEONIsFastFBWorking(ScrnInfoPtr pScrn)
 {
     RADEONInfoPtr info = RADEONPTR(pScrn);
@@ -1564,7 +1613,10 @@ static Bool RADEONCloseScreen_KMS(CLOSE_SCREEN_ARGS_DECL)
     radeon_drm_queue_close(pScrn);
     radeon_cs_flush_indirect(pScrn);

-    DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn);
+    if (info->callback_event_type != -1) {
+	DeleteCallback(&EventCallback, radeon_event_callback, pScrn);
+	DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn);
+    }

     if (info->accel_state->exa) {
 	exaDriverFini(pScreen);
@@ -1838,9 +1890,6 @@ Bool RADEONScreenInit_KMS(SCREEN_INIT_ARGS_DECL)
     info->BlockHandler = pScreen->BlockHandler;
     pScreen->BlockHandler = RADEONBlockHandler_oneshot;

-    if (!AddCallback(&FlushCallback, radeon_flush_callback, pScrn))
-        return FALSE;
-
     info->CreateScreenResources = pScreen->CreateScreenResources;
     pScreen->CreateScreenResources = RADEONCreateScreenResources_KMS;

