From: Michel Dänzer <michel.daenzer@amd.com>
Date: Mon Jul 11 12:51:46 2016 +0900
Subject: [PATCH 11/20]Keep track of damage event related flushes per-client v2
Patch-mainline: Upstream
Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati
Git-commit: 121a6de72da5fcf9a32408eff36b2235f3dfbcfe
References: bsc#990066
Signed-off-by: Max Staudt <mstaudt@suse.de>

This further reduces the compositing slowdown due to flushing overhead,
by only flushing when the X server actually sends XDamageNotify events
to a client, and there hasn't been a flush yet in the meantime.

v2: Use ScreenPrivateKey, fixes invalid memory access with GPU screens
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
---
 src/radeon.h     |  5 ++++-
 src/radeon_kms.c | 41 +++++++++++++++++++++++++++++++++--------
 2 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/src/radeon.h b/src/radeon.h
index 25ff61c..f3a3e1c 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -448,6 +448,10 @@ struct radeon_accel_state {
     Bool              force;
 };

+struct radeon_client_priv {
+    uint_fast32_t     needs_flush;
+};
+
 typedef struct {
     EntityInfoPtr     pEnt;
     pciVideoPtr       PciInfo;
@@ -474,7 +478,6 @@ typedef struct {
     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 f778d30..136c46c 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -40,6 +40,7 @@

 #include "radeon_version.h"
 #include "shadow.h"
+#include <xf86Priv.h>

 #include "atipciids.h"

@@ -59,6 +60,8 @@
 #include "radeon_cs_gem.h"
 #include "radeon_vbo.h"

+static DevScreenPrivateKeyRec radeon_client_private_key;
+
 extern SymTabRec RADEONChipsets[];
 static Bool radeon_setup_kernel_mem(ScreenPtr pScreen);

@@ -241,9 +244,9 @@ radeonUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
 }

 static Bool
-callback_needs_flush(RADEONInfoPtr info)
+callback_needs_flush(RADEONInfoPtr info, struct radeon_client_priv *client_priv)
 {
-    return (int)(info->callback_needs_flush - info->gpu_flushed) > 0;
+    return (int)(client_priv->needs_flush - info->gpu_flushed) > 0;
 }

 static void
@@ -252,20 +255,30 @@ radeon_event_callback(CallbackListPtr *list,
 {
     EventInfoRec *eventinfo = call_data;
     ScrnInfoPtr pScrn = user_data;
+    ScreenPtr pScreen = pScrn->pScreen;
+    struct radeon_client_priv *client_priv =
+	dixLookupScreenPrivate(&eventinfo->client->devPrivates,
+			       &radeon_client_private_key, pScreen);
+    struct radeon_client_priv *server_priv =
+	dixLookupScreenPrivate(&serverClient->devPrivates,
+			       &radeon_client_private_key, pScreen);
     RADEONInfoPtr info = RADEONPTR(pScrn);
     int i;

-    if (callback_needs_flush(info))
+    if (callback_needs_flush(info, client_priv) ||
+	callback_needs_flush(info, server_priv))
 	return;

-    /* Don't let gpu_flushed get too far ahead of callback_needs_flush,
-     * in order to prevent false positives in callback_needs_flush()
+    /* Don't let gpu_flushed get too far ahead of needs_flush, in order
+     * to prevent false positives in callback_needs_flush()
      */
-    info->callback_needs_flush = info->gpu_flushed;
+    client_priv->needs_flush = info->gpu_flushed;
+    server_priv->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++;
+	    client_priv->needs_flush++;
+	    server_priv->needs_flush++;
 	    return;
 	}
     }
@@ -276,9 +289,14 @@ radeon_flush_callback(CallbackListPtr *list,
 		      pointer user_data, pointer call_data)
 {
     ScrnInfoPtr pScrn = user_data;
+    ScreenPtr pScreen = pScrn->pScreen;
+    ClientPtr client = call_data ? call_data : serverClient;
+    struct radeon_client_priv *client_priv =
+	dixLookupScreenPrivate(&client->devPrivates,
+			       &radeon_client_private_key, pScreen);
     RADEONInfoPtr info = RADEONPTR(pScrn);

-    if (pScrn->vtSema && callback_needs_flush(info))
+    if (pScrn->vtSema && callback_needs_flush(info, client_priv))
         radeon_cs_flush_indirect(pScrn);
 }

@@ -351,6 +369,13 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen)
 	    DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn);
 	    return FALSE;
 	}
+
+	if (!dixRegisterScreenPrivateKey(&radeon_client_private_key, pScreen,
+					 PRIVATE_CLIENT, sizeof(struct radeon_client_priv))) {
+	    DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn);
+	    DeleteCallback(&EventCallback, radeon_event_callback, pScrn);
+	    return FALSE;
+	}
     }

     return TRUE;
