[PATCH xf86-video-amdgpu 09/11] glamor: Add Option "ShadowPrimary"

Michel Dänzer michel at daenzer.net
Wed Jun 10 02:04:24 PDT 2015


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

When this option is enabled, most pixmaps (including the screen pixmap)
are allocated in system RAM and mostly accessed by the CPU. Changed areas
of the screen pixmap are copied to dedicated per-CRTC scanout pixmaps
regularly, triggered by the vblank interrupt.

(Cherry picked from radeon commits ae92d1765fa370a8d94c2856ad6c45d273ec3c69
and 1af044d7eee211fd4b248c236280274a68334da5)

[ Michel Dänzer: Additional adjustements for the amdgpu driver ]

Signed-off-by: Darren Powell <darren.powell at amd.com>
Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 configure.ac          |  10 +++
 man/amdgpu.man        |  35 ++++++++---
 src/amdgpu_dri2.c     |   1 +
 src/amdgpu_dri3.c     |   3 +-
 src/amdgpu_drv.h      |   2 +
 src/amdgpu_glamor.c   |  62 ++++++++++++++++---
 src/amdgpu_glamor.h   |   9 +++
 src/amdgpu_kms.c      | 167 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/drmmode_display.c | 150 +++++++++++++++++++++++++++++++++------------
 src/drmmode_display.h |   6 ++
 10 files changed, 381 insertions(+), 64 deletions(-)

diff --git a/configure.ac b/configure.ac
index d9d97ef..85892fa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -145,6 +145,16 @@ else
 fi
 AM_CONDITIONAL(GLAMOR, test x$GLAMOR != xno)
 
+AC_CHECK_DECL(fbGlyphs,
+	      [AC_DEFINE(HAVE_FBGLYPHS, 1, [Have fbGlyphs API])], [],
+	      [#include <X11/Xmd.h>
+	       #include <X11/Xfuncproto.h>
+	       #include <X11/extensions/renderproto.h>
+	       #include <xorg-server.h>
+	       #include <picture.h>
+	       #include <glyphstr.h>
+	       #include <fbpict.h>])
+
 AC_CHECK_DECL(xorg_list_init,
 	      [AC_DEFINE(HAVE_XORG_LIST, 1, [Have xorg_list API])], [],
 	      [#include <X11/Xdefs.h>
diff --git a/man/amdgpu.man b/man/amdgpu.man
index bc7bf30..d280197 100644
--- a/man/amdgpu.man
+++ b/man/amdgpu.man
@@ -50,15 +50,7 @@ Enables or disables all hardware acceleration.
 The default is to
 .B enable
 hardware acceleration.
-.TP
-.BI "Option \*qAccelMethod\*q \*q" string \*q
-Setting this option to
-.B none
-disables use of the glamor acceleration architecture. In that case, all 2D
-rendering is done by the CPU, but 3D and video hardware acceleration can still
-work. This is mainly useful for OpenGL driver bring-up.
-.br
-The default is to use glamor.
+
 .TP
 .BI "Option \*qZaphodHeads\*q \*q" string \*q
 Specify the RandR output(s) to use with zaphod mode for a particular driver
@@ -77,6 +69,31 @@ Enable the DRI3 extension. The default is
 .BI "Option \*qEnablePageFlip\*q \*q" boolean \*q
 Enable DRI2 page flipping.  The default is
 .B on.
+.TP
+.BI "Option \*qAccelMethod\*q \*q" string \*q
+Setting this option to
+.B none
+disables use of the glamor acceleration architecture. In that case, all 2D
+rendering is done by the CPU, but 3D and video hardware acceleration can still
+work. This is mainly useful for OpenGL driver bring-up.
+.br
+The default is to use glamor.
+
+.PP
+The following driver
+.B Option
+is supported for
+.B glamor
+:
+.TP
+.BI "Option \*qShadowPrimary\*q \*q" boolean \*q
+This option enables a so-called "shadow primary" buffer for fast CPU access to
+pixel data, and separate scanout buffers for each display controller (CRTC).
+This may improve performance for some 2D workloads, potentially at the expense
+of other (e.g. 3D, video) workloads.
+Note in particular that enabling this option currently disables page flipping.
+The default is
+.B off.
 
 .SH SEE ALSO
 __xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__)
diff --git a/src/amdgpu_dri2.c b/src/amdgpu_dri2.c
index 28c56e7..bdb0d37 100644
--- a/src/amdgpu_dri2.c
+++ b/src/amdgpu_dri2.c
@@ -116,6 +116,7 @@ static PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap)
 				   old->drawable.width,
 				   old->drawable.height,
 				   0, 0, priv->stride, NULL);
+	old->devPrivate.ptr = NULL;
 
 	return old;
 }
diff --git a/src/amdgpu_dri3.c b/src/amdgpu_dri3.c
index ce0f8e7..a89421e 100644
--- a/src/amdgpu_dri3.c
+++ b/src/amdgpu_dri3.c
@@ -108,7 +108,8 @@ static PixmapPtr amdgpu_dri3_pixmap_from_fd(ScreenPtr screen,
 		return NULL;
 	}
 
-	pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
+	pixmap = screen->CreatePixmap(screen, 0, 0, depth,
+				      AMDGPU_CREATE_PIXMAP_DRI2);
 	if (!pixmap)
 		return NULL;
 
diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h
index 467c2fb..55be626 100644
--- a/src/amdgpu_drv.h
+++ b/src/amdgpu_drv.h
@@ -142,6 +142,7 @@ typedef enum {
 	OPTION_ZAPHOD_HEADS,
 	OPTION_ACCEL_METHOD,
 	OPTION_DRI3,
+	OPTION_SHADOW_PRIMARY,
 } AMDGPUOpts;
 
 #define AMDGPU_VSYNC_TIMEOUT	20000	/* Maximum wait for VSYNC (in usecs) */
@@ -203,6 +204,7 @@ typedef struct {
 	uint_fast32_t gpu_flushed;
 	uint_fast32_t gpu_synced;
 	Bool use_glamor;
+	Bool shadow_primary;
 
 	/* general */
 	OptionInfoPtr Options;
diff --git a/src/amdgpu_glamor.c b/src/amdgpu_glamor.c
index d91effc..0c100d4 100644
--- a/src/amdgpu_glamor.c
+++ b/src/amdgpu_glamor.c
@@ -146,25 +146,27 @@ amdgpu_glamor_create_textured_pixmap(PixmapPtr pixmap, struct amdgpu_pixmap *pri
 						 pixmap->devKind);
 }
 
-#ifndef CREATE_PIXMAP_USAGE_SHARED
-#define CREATE_PIXMAP_USAGE_SHARED AMDGPU_CREATE_PIXMAP_DRI2
-#endif
-
-#define AMDGPU_CREATE_PIXMAP_SHARED(usage) \
-	((usage) & AMDGPU_CREATE_PIXMAP_DRI2 || (usage) == CREATE_PIXMAP_USAGE_SHARED)
-
 static PixmapPtr
 amdgpu_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 			    unsigned usage)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	struct amdgpu_pixmap *priv;
 	PixmapPtr pixmap, new_pixmap = NULL;
 
 	if (!AMDGPU_CREATE_PIXMAP_SHARED(usage)) {
-		pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
-		if (pixmap)
-			return pixmap;
+		if (info->shadow_primary) {
+			if (usage != CREATE_PIXMAP_USAGE_BACKING_PIXMAP)
+				return fbCreatePixmap(screen, w, h, depth, usage);
+
+			usage |= AMDGPU_CREATE_PIXMAP_LINEAR |
+				 AMDGPU_CREATE_PIXMAP_GTT;
+		} else {
+			pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
+			if (pixmap)
+				return pixmap;
+		}
 	}
 
 	if (w > 32767 || h > 32767)
@@ -196,6 +198,8 @@ amdgpu_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, priv->stride,
 					   NULL);
 
+		pixmap->devPrivate.ptr = NULL;
+
 		if (!amdgpu_glamor_create_textured_pixmap(pixmap, priv))
 			goto fallback_glamor;
 	}
@@ -236,6 +240,13 @@ fallback_pixmap:
 static Bool amdgpu_glamor_destroy_pixmap(PixmapPtr pixmap)
 {
 	if (pixmap->refcnt == 1) {
+		if (pixmap->devPrivate.ptr) {
+			struct amdgpu_buffer *bo = amdgpu_get_pixmap_bo(pixmap);
+
+			if (bo)
+				amdgpu_bo_unmap(bo);
+		}
+
 		glamor_egl_destroy_textured_pixmap(pixmap);
 		amdgpu_set_pixmap_bo(pixmap, NULL);
 	}
@@ -289,6 +300,26 @@ amdgpu_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle)
 Bool amdgpu_glamor_init(ScreenPtr screen)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+#ifdef RENDER
+#ifdef HAVE_FBGLYPHS
+	UnrealizeGlyphProcPtr SavedUnrealizeGlyph = NULL;
+#endif
+	PictureScreenPtr ps = NULL;
+
+	if (info->shadow_primary) {
+		ps = GetPictureScreenIfSet(screen);
+
+		if (ps) {
+#ifdef HAVE_FBGLYPHS
+			SavedUnrealizeGlyph = ps->UnrealizeGlyph;
+#endif
+			info->glamor.SavedGlyphs = ps->Glyphs;
+			info->glamor.SavedTriangles = ps->Triangles;
+			info->glamor.SavedTrapezoids = ps->Trapezoids;
+		}
+	}
+#endif /* RENDER */
 
 	if (!glamor_init(screen, GLAMOR_USE_EGL_SCREEN | GLAMOR_USE_SCREEN |
 			 GLAMOR_USE_PICTURE_SCREEN | GLAMOR_INVERTED_Y_AXIS |
@@ -310,6 +341,17 @@ Bool amdgpu_glamor_init(ScreenPtr screen)
 #endif
 		return FALSE;
 
+	if (info->shadow_primary)
+		amdgpu_glamor_screen_init(screen);
+
+#if defined(RENDER) && defined(HAVE_FBGLYPHS)
+	/* For ShadowPrimary, we need fbUnrealizeGlyph instead of
+	 * glamor_unrealize_glyph
+	 */
+	if (ps)
+		ps->UnrealizeGlyph = SavedUnrealizeGlyph;
+#endif
+
 	screen->CreatePixmap = amdgpu_glamor_create_pixmap;
 	screen->DestroyPixmap = amdgpu_glamor_destroy_pixmap;
 #ifdef AMDGPU_PIXMAP_SHARING
diff --git a/src/amdgpu_glamor.h b/src/amdgpu_glamor.h
index 7959e9d..a781695 100644
--- a/src/amdgpu_glamor.h
+++ b/src/amdgpu_glamor.h
@@ -32,6 +32,14 @@
 #define GLAMOR_FOR_XORG  1
 #include <glamor.h>
 
+#ifndef CREATE_PIXMAP_USAGE_SHARED
+#define CREATE_PIXMAP_USAGE_SHARED AMDGPU_CREATE_PIXMAP_DRI2
+#endif
+
+#define AMDGPU_CREATE_PIXMAP_SHARED(usage) \
+	((usage) == AMDGPU_CREATE_PIXMAP_DRI2 || \
+	 (usage) == CREATE_PIXMAP_USAGE_SHARED)
+
 #ifndef GLAMOR_NO_DRI3
 #define GLAMOR_NO_DRI3 0
 #define glamor_fd_from_pixmap glamor_dri3_fd_from_pixmap
@@ -52,6 +60,7 @@ struct amdgpu_pixmap;
 
 Bool amdgpu_glamor_pre_init(ScrnInfoPtr scrn);
 Bool amdgpu_glamor_init(ScreenPtr screen);
+void amdgpu_glamor_screen_init(ScreenPtr screen);
 Bool amdgpu_glamor_create_screen_resources(ScreenPtr screen);
 void amdgpu_glamor_free_screen(int scrnIndex, int flags);
 
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index cfdf716..5a672c9 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -67,6 +67,7 @@ const OptionInfoRec AMDGPUOptions_KMS[] = {
 	{OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE},
 	{OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
 	{ OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE },
+	{OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE},
 	{-1, NULL, OPTV_NONE, {0}, FALSE}
 };
 
@@ -210,6 +211,134 @@ static void amdgpu_dirty_update(ScreenPtr screen)
 }
 #endif
 
+static Bool
+amdgpu_scanout_extents_intersect(BoxPtr extents, int x, int y, int w, int h)
+{
+	extents->x1 = max(extents->x1 - x, 0);
+	extents->y1 = max(extents->y1 - y, 0);
+	extents->x2 = min(extents->x2 - x, w);
+	extents->y2 = min(extents->y2 - y, 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)
+{
+	xf86CrtcPtr xf86_crtc = event_data;
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+	DamagePtr pDamage;
+	RegionPtr pRegion;
+	DrawablePtr pDraw;
+	ScreenPtr pScreen;
+	GCPtr gc;
+	BoxRec extents;
+
+	if (!drmmode_crtc->scanout.pixmap ||
+	    drmmode_crtc->dpms_mode != DPMSModeOn)
+		goto out;
+
+	pDamage = drmmode_crtc->scanout_damage;
+	if (!pDamage)
+		goto out;
+
+	pRegion = DamageRegion(pDamage);
+	if (!RegionNotEmpty(pRegion))
+		goto out;
+
+	pDraw = &drmmode_crtc->scanout.pixmap->drawable;
+	extents = *RegionExtents(pRegion);
+	if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
+					      pDraw->width, pDraw->height))
+		goto clear_damage;
+
+	pScreen = pDraw->pScreen;
+	gc = GetScratchGC(pDraw->depth, pScreen);
+
+	ValidateGC(pDraw, gc);
+	(*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable,
+			     pDraw, gc,
+			     xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
+			     extents.x2 - extents.x1, extents.y2 - extents.y1,
+			     extents.x1, extents.y1);
+	FreeScratchGC(gc);
+
+	amdgpu_glamor_flush(scrn);
+
+clear_damage:
+	RegionEmpty(pRegion);
+
+out:
+	drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+	struct amdgpu_drm_queue_entry *drm_queue_entry;
+	ScrnInfoPtr scrn;
+	drmVBlank vbl;
+	DamagePtr pDamage;
+	RegionPtr pRegion;
+	DrawablePtr pDraw;
+	BoxRec extents;
+
+	if (drmmode_crtc->scanout_update_pending ||
+	    !drmmode_crtc->scanout.pixmap ||
+	    drmmode_crtc->dpms_mode != DPMSModeOn)
+		return;
+
+	pDamage = drmmode_crtc->scanout_damage;
+	if (!pDamage)
+		return;
+
+	pRegion = DamageRegion(pDamage);
+	if (!RegionNotEmpty(pRegion))
+		return;
+
+	pDraw = &drmmode_crtc->scanout.pixmap->drawable;
+	extents = *RegionExtents(pRegion);
+	if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
+					      pDraw->width, pDraw->height))
+		return;
+
+	scrn = xf86_crtc->scrn;
+	drm_queue_entry = amdgpu_drm_queue_alloc(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
+						 AMDGPU_DRM_QUEUE_ID_DEFAULT,
+						 xf86_crtc,
+						 amdgpu_scanout_update_handler,
+						 amdgpu_scanout_update_abort);
+	if (!drm_queue_entry) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			   "amdgpu_drm_queue_alloc failed for scanout update\n");
+		return;
+	}
+
+	vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
+	vbl.request.type |= amdgpu_populate_vbl_request_type(xf86_crtc);
+	vbl.request.sequence = 1;
+	vbl.request.signal = (unsigned long)drm_queue_entry;
+	if (drmWaitVBlank(AMDGPUPTR(scrn)->dri2.drm_fd, &vbl)) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			   "drmWaitVBlank failed for scanout update: %s\n",
+			   strerror(errno));
+		amdgpu_drm_abort_entry(drm_queue_entry);
+		return;
+	}
+
+	drmmode_crtc->scanout_update_pending = TRUE;
+}
 static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
 {
 	SCREEN_PTR(arg);
@@ -220,6 +349,14 @@ static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
 	(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
 	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
 
+	if (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]);
+	}
+
 	if (info->use_glamor)
 		amdgpu_glamor_flush(pScrn);
 
@@ -543,12 +680,28 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
 		amdgpu_get_tile_config(pScrn);
 	}
 
+	if (info->use_glamor) {
+		info->shadow_primary =
+			xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE);
+
+		if (info->shadow_primary)
+			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowPrimary enabled\n");
+	}
+
 	info->allowPageFlip = xf86ReturnOptValBool(info->Options,
 						   OPTION_PAGE_FLIP,
 						   TRUE);
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-		   "KMS Pageflipping: %sabled\n",
-		   info->allowPageFlip ? "en" : "dis");
+	if (info->shadow_primary) {
+		    xf86DrvMsg(pScrn->scrnIndex,
+			       info->allowPageFlip ? X_WARNING : X_DEFAULT,
+			       "KMS Pageflipping: disabled%s\n",
+			       info->allowPageFlip ? " because of ShadowPrimary" : "");
+		    info->allowPageFlip = FALSE;
+	} else {
+		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+			   "KMS Pageflipping: %sabled\n",
+			   info->allowPageFlip ? "en" : "dis");
+	}
 
 	if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) ==
 	    FALSE) {
@@ -993,6 +1146,7 @@ void AMDGPULeaveVT_KMS(VT_FUNC_ARGS_DECL)
 	drmDropMaster(info->dri2.drm_fd);
 
 	xf86RotateFreeShadow(pScrn);
+	drmmode_scanout_free(pScrn);
 
 	xf86_hide_cursors(pScrn);
 
@@ -1074,7 +1228,12 @@ static Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen)
 
 	if (info->front_buffer == NULL) {
 		int pitch;
-		int hint = info->use_glamor ? 0 : AMDGPU_CREATE_PIXMAP_LINEAR;
+		int hint = 0;
+
+		if (info->shadow_primary)
+			hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
+		else if (!info->use_glamor)
+			hint = AMDGPU_CREATE_PIXMAP_LINEAR;
 
 		info->front_buffer =
 			amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 1fcf901..79fbecf 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -32,6 +32,8 @@
 #include <errno.h>
 #include <sys/ioctl.h>
 #include <time.h>
+#include "cursorstr.h"
+#include "damagestr.h"
 #include "micmap.h"
 #include "xf86cmap.h"
 #include "sarea.h"
@@ -302,17 +304,8 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
 	uint32_t size = pScrn->displayWidth * info->pixel_bytes * pScrn->virtualY;
 
 	/* memset the bo */
-	if (info->gbm) {
-		void *cpu_ptr = malloc(size);
-
-		if (cpu_ptr) {
-			memset(cpu_ptr, 0x00, size);
-			gbm_bo_write(info->front_buffer->bo.gbm, cpu_ptr, size);
-			free(cpu_ptr);
-		}
-	} else {
-		memset(info->front_buffer->cpu_ptr, 0x00, size);
-	}
+	amdgpu_bo_map(pScrn, info->front_buffer);
+	memset(info->front_buffer->cpu_ptr, 0x00, size);
 }
 
 static void
@@ -334,6 +327,26 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
 
 }
 
+void
+drmmode_scanout_free(ScrnInfoPtr scrn)
+{
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+	int c;
+
+	for (c = 0; c < xf86_config->num_crtc; c++) {
+		drmmode_crtc_private_ptr drmmode_crtc =
+			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;
+		}
+	}
+}
+
 static void *
 drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
                               struct drmmode_scanout *scanout,
@@ -354,6 +367,13 @@ drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
 		return NULL;
 	}
 
+	if (scanout->bo) {
+		if (scanout->width == width && scanout->height == height)
+			return scanout->bo;
+
+		drmmode_crtc_scanout_destroy(drmmode, scanout);
+	}
+
 	scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height,
 					       pScrn->depth, 0,
 					       pScrn->bitsPerPixel, &pitch);
@@ -371,6 +391,8 @@ drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
 		ErrorF("failed to add rotate fb\n");
 	}
 
+	scanout->width = width;
+	scanout->height = height;
 	return scanout->bo;
 }
 
@@ -380,8 +402,17 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc,
                             void *data, int width, int height)
 {
 	ScrnInfoPtr pScrn = crtc->scrn;
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
 	unsigned long rotate_pitch;
 
+	if (scanout->pixmap) {
+		if (scanout->width == width && scanout->height == height)
+			return scanout->pixmap;
+
+		drmmode_crtc_scanout_destroy(drmmode, scanout);
+	}
+
 	if (!data)
 		data = drmmode_crtc_scanout_allocate(crtc, scanout, width, height);
 
@@ -401,6 +432,13 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc,
 
 }
 
+static void
+amdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
+{
+	/* Only keep track of the extents */
+	RegionUninit(&damage->damage);
+	damage->damage.data = NULL;
+}
 
 static Bool
 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
@@ -460,6 +498,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 	}
 
 	if (mode) {
+		ScreenPtr pScreen = pScrn->pScreen;
+
 		for (i = 0; i < xf86_config->num_output; i++) {
 			xf86OutputPtr output = xf86_config->output[i];
 			drmmode_output_private_ptr drmmode_output;
@@ -486,11 +526,46 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
 			x = drmmode_crtc->prime_pixmap_x;
 			y = 0;
+
+			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout);
 		} 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);
+				}
+
+				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);
+
+				fb_id = drmmode_crtc->scanout.fb_id;
+				x = y = 0;
+			}
 		}
 		ret =
 		    drmModeSetCrtc(drmmode->fd,
@@ -1313,18 +1388,23 @@ static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
 	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	struct amdgpu_buffer *old_front = NULL;
-	Bool ret;
 	ScreenPtr screen = xf86ScrnToScreen(scrn);
 	uint32_t old_fb_id;
 	int i, pitch, old_width, old_height, old_pitch;
 	int cpp = info->pixel_bytes;
 	PixmapPtr ppix = screen->GetScreenPixmap(screen);
+	uint32_t bo_handle;
 	void *fb_shadow;
-	int hint = info->use_glamor ? 0 : AMDGPU_CREATE_PIXMAP_LINEAR;
+	int hint = 0;
 
 	if (scrn->virtualX == width && scrn->virtualY == height)
 		return TRUE;
 
+	if (info->shadow_primary)
+		hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
+	else if (!info->use_glamor)
+		hint = AMDGPU_CREATE_PIXMAP_LINEAR;
+
 	xf86DrvMsg(scrn->scrnIndex, X_INFO,
 		   "Allocate new frame buffer %dx%d\n", width, height);
 
@@ -1356,35 +1436,26 @@ static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
 	xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch);
 	scrn->displayWidth = pitch / cpp;
 
-	if (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM) {
-		union gbm_bo_handle bo_handle;
+	if (!amdgpu_bo_get_handle(info->front_buffer, &bo_handle)) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "Failed to get front buffer handle\n");
+		goto fail;
+	}
 
-		bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm);
-		ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
-				   scrn->bitsPerPixel, pitch,
-				   bo_handle.u32, &drmmode->fb_id);
-		if (ret) {
-			goto fail;
-		}
+	if (drmModeAddFB(drmmode->fd, width, height, scrn->depth,
+			 scrn->bitsPerPixel, pitch,
+			 bo_handle, &drmmode->fb_id) != 0) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "drmModeAddFB failed for front buffer\n");
+		goto fail;
+	}
 
+	if (info->use_glamor ||
+	    (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) {
 		amdgpu_set_pixmap_bo(ppix, info->front_buffer);
 		screen->ModifyPixmapHeader(ppix,
 					   width, height, -1, -1, pitch, info->front_buffer->cpu_ptr);
 	} else {
-		uint32_t bo_handle;
-
-		if (amdgpu_bo_export(info->front_buffer->bo.amdgpu,
-				     amdgpu_bo_handle_type_kms,
-				     &bo_handle)) {
-			goto fail;
-		}
-		ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
-				   scrn->bitsPerPixel, pitch,
-				   bo_handle, &drmmode->fb_id);
-		if (ret) {
-			goto fail;
-		}
-
 		fb_shadow = calloc(1, pitch * scrn->virtualY);
 		if (fb_shadow == NULL)
 			goto fail;
@@ -1800,7 +1871,6 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 			int ref_crtc_hw_id, amdgpu_drm_handler_proc handler,
 			amdgpu_drm_abort_proc abort)
 {
-	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
 	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
@@ -1813,9 +1883,9 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 	union gbm_bo_handle bo_handle;
 	uint32_t handle;
 
-	if (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM) {
-		pitch = gbm_bo_get_stride(info->front_buffer->bo.gbm);
-		height = gbm_bo_get_height(info->front_buffer->bo.gbm);
+	if (new_front->flags & AMDGPU_BO_FLAGS_GBM) {
+		pitch = gbm_bo_get_stride(new_front->bo.gbm);
+		height = gbm_bo_get_height(new_front->bo.gbm);
 		bo_handle = gbm_bo_get_handle(new_front->bo.gbm);
 		handle = bo_handle.u32;
 	} else {
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 77d9c03..0ba358e 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -74,6 +74,7 @@ struct drmmode_scanout {
 	struct amdgpu_buffer *bo;
 	PixmapPtr pixmap;
 	unsigned fb_id;
+	int width, height;
 };
 
 typedef struct {
@@ -82,6 +83,9 @@ typedef struct {
 	int hw_id;
 	struct amdgpu_buffer *cursor_buffer;
 	struct drmmode_scanout rotate;
+	struct drmmode_scanout scanout;
+	DamagePtr scanout_damage;
+	Bool scanout_update_pending;
 	int dpms_mode;
 	CARD64 dpms_last_ust;
 	uint32_t dpms_last_seq;
@@ -121,6 +125,8 @@ extern Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
 extern void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
 extern Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn);
 
+extern void drmmode_scanout_free(ScrnInfoPtr scrn);
+
 extern void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode);
 extern void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode);
 
-- 
2.1.4



More information about the xorg-driver-ati mailing list