[PATCH xf86-video-amdgpu 02/12] Use EventCallback to avoid flushing every time in the FlushCallback

Michel Dänzer michel at daenzer.net
Thu Sep 8 10:02:35 UTC 2016


From: Michel Dänzer <michel.daenzer at amd.com>

We only need to flush for XDamageNotify events.

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

(Ported from radeon commit 9a1afbf61fbb2827c86bd86d295fa0848980d60b)

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/amdgpu_drv.h    |  2 ++
 src/amdgpu_glamor.c |  3 ++-
 src/amdgpu_kms.c    | 77 ++++++++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 66 insertions(+), 16 deletions(-)

diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h
index 60aa0be..d2b3a6b 100644
--- a/src/amdgpu_drv.h
+++ b/src/amdgpu_drv.h
@@ -209,6 +209,8 @@ typedef struct {
 
 	/* accel */
 	PixmapPtr fbcon_pixmap;
+	int callback_event_type;
+	uint_fast32_t callback_needs_flush;
 	uint_fast32_t gpu_flushed;
 	uint_fast32_t gpu_synced;
 	Bool use_glamor;
diff --git a/src/amdgpu_glamor.c b/src/amdgpu_glamor.c
index 62831d0..d29b096 100644
--- a/src/amdgpu_glamor.c
+++ b/src/amdgpu_glamor.c
@@ -460,8 +460,9 @@ void amdgpu_glamor_flush(ScrnInfoPtr pScrn)
 
 	if (info->use_glamor) {
 		glamor_block_handler(pScrn->pScreen);
-		info->gpu_flushed++;
 	}
+
+	info->gpu_flushed++;
 }
 
 void amdgpu_glamor_finish(ScrnInfoPtr pScrn)
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index 9f023cf..b1f6bd7 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -50,6 +50,8 @@
 #include <X11/extensions/dpms.h>
 #endif
 
+#include <X11/extensions/damageproto.h>
+
 #include "amdgpu_chipinfo_gen.h"
 #include "amdgpu_bo_helper.h"
 #include "amdgpu_pixmap.h"
@@ -163,8 +165,51 @@ amdgpuUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
 	shadowUpdatePacked(pScreen, pBuf);
 }
 
+static Bool
+callback_needs_flush(AMDGPUInfoPtr info)
+{
+	return (int)(info->callback_needs_flush - info->gpu_flushed) > 0;
+}
+
+static void
+amdgpu_event_callback(CallbackListPtr *list,
+		      pointer user_data, pointer call_data)
+{
+	EventInfoRec *eventinfo = call_data;
+	ScrnInfoPtr pScrn = user_data;
+	AMDGPUInfoPtr info = AMDGPUPTR(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
+amdgpu_flush_callback(CallbackListPtr *list,
+		      pointer user_data, pointer call_data)
+{
+	ScrnInfoPtr pScrn = user_data;
+	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
+
+	if (pScrn->vtSema && callback_needs_flush(info))
+		amdgpu_glamor_flush(pScrn);
+}
+
 static Bool AMDGPUCreateScreenResources_KMS(ScreenPtr pScreen)
 {
+	ExtensionEntry *damage_ext = CheckExtension("DAMAGE");
 	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
 	PixmapPtr pixmap;
@@ -217,6 +262,19 @@ static Bool AMDGPUCreateScreenResources_KMS(ScreenPtr pScreen)
 	if (info->use_glamor)
 		amdgpu_glamor_create_screen_resources(pScreen);
 
+	info->callback_event_type = -1;
+	if (damage_ext) {
+		info->callback_event_type = damage_ext->eventBase + XDamageNotify;
+
+		if (!AddCallback(&FlushCallback, amdgpu_flush_callback, pScrn))
+			return FALSE;
+
+		if (!AddCallback(&EventCallback, amdgpu_event_callback, pScrn)) {
+			DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
+			return FALSE;
+		}
+	}
+
 	return TRUE;
 }
 
@@ -542,17 +600,6 @@ static void AMDGPUBlockHandler_oneshot(BLOCKHANDLER_ARGS_DECL)
 	drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE);
 }
 
-static void
-amdgpu_flush_callback(CallbackListPtr * list,
-		      pointer user_data, pointer call_data)
-{
-	ScrnInfoPtr pScrn = user_data;
-
-	if (pScrn->vtSema) {
-		amdgpu_glamor_flush(pScrn);
-	}
-}
-
 /* This is called by AMDGPUPreInit to set up the default visual */
 static Bool AMDGPUPreInitVisual(ScrnInfoPtr pScrn)
 {
@@ -1108,7 +1155,10 @@ static Bool AMDGPUCloseScreen_KMS(CLOSE_SCREEN_ARGS_DECL)
 	drmmode_uevent_fini(pScrn, &info->drmmode);
 	amdgpu_drm_queue_close(pScrn);
 
-	DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
+	if (info->callback_event_type != -1) {
+		DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn);
+		DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
+	}
 
 	amdgpu_sync_close(pScreen);
 	amdgpu_drop_drm_master(pScrn);
@@ -1347,9 +1397,6 @@ Bool AMDGPUScreenInit_KMS(SCREEN_INIT_ARGS_DECL)
 	info->BlockHandler = pScreen->BlockHandler;
 	pScreen->BlockHandler = AMDGPUBlockHandler_oneshot;
 
-	if (!AddCallback(&FlushCallback, amdgpu_flush_callback, pScrn))
-		return FALSE;
-
 	info->CreateScreenResources = pScreen->CreateScreenResources;
 	pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS;
 
-- 
2.9.3



More information about the amd-gfx mailing list