[PATCH 7/7] glamor: Add Option "ShadowPrimary"

Michel Dänzer michel at daenzer.net
Wed Apr 1 03:04:49 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.

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 configure.ac           |  10 +++
 man/radeon.man         |  16 +++++
 src/drmmode_display.c  |  86 +++++++++++++++++++++++-
 src/drmmode_display.h  |   6 ++
 src/radeon.h           |   2 +
 src/radeon_bo_helper.c |   7 +-
 src/radeon_dri3.c      |  15 ++++-
 src/radeon_glamor.c    |  60 ++++++++++++++---
 src/radeon_glamor.h    |  10 +++
 src/radeon_kms.c       | 179 +++++++++++++++++++++++++++++++++++++++++++++++--
 10 files changed, 369 insertions(+), 22 deletions(-)

diff --git a/configure.ac b/configure.ac
index 57b4c1c..4ca5352 100644
--- a/configure.ac
+++ b/configure.ac
@@ -125,6 +125,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/radeon.man b/man/radeon.man
index 6e46f89..2703773 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -290,6 +290,22 @@ as of TAHITI, otherwise
 The following driver
 .B Options
 are 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.
+
+.PP
+The following driver
+.B Options
+are supported for
 .B EXA
 :
 .TP
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index d8d3ca3..efe82bd 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -33,6 +33,7 @@
 #include <sys/ioctl.h>
 #include <time.h>
 #include "cursorstr.h"
+#include "damagestr.h"
 #include "micmap.h"
 #include "xf86cmap.h"
 #include "radeon.h"
@@ -489,6 +490,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,
@@ -510,6 +531,13 @@ drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
 		return NULL;
 	}
 
+	if (scanout->bo) {
+		if (scanout->width == width && scanout->height == height)
+			return scanout->bo->ptr;
+
+		drmmode_crtc_scanout_destroy(drmmode, scanout);
+	}
+
 	rotate_pitch =
 		RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0))
 		* drmmode->cpp;
@@ -531,6 +559,8 @@ drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
 	if (ret)
 		ErrorF("failed to add scanout fb\n");
 
+	scanout->width = width;
+	scanout->height = height;
 	return scanout->bo->ptr;
 }
 
@@ -543,6 +573,13 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
 	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);
 
@@ -562,6 +599,13 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
 	return scanout->pixmap;
 }
 
+static void
+radeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
+{
+	/* Only keep track of the extents */
+	RegionUninit(&damage->damage);
+}
+
 static Bool
 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		     Rotation rotation, int x, int y)
@@ -631,6 +675,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;
@@ -656,11 +702,44 @@ 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) {
+			RegionPtr pRegion;
+			BoxPtr pBox;
+
+			drmmode_crtc_scanout_create(crtc,
+						    &drmmode_crtc->scanout,
+						    NULL, mode->HDisplay,
+						    mode->VDisplay);
+
+			if (drmmode_crtc->scanout.pixmap) {
+				if (!drmmode_crtc->scanout_damage) {
+					drmmode_crtc->scanout_damage =
+						DamageCreate(radeon_screen_damage_report,
+							     NULL, DamageReportRawRegion,
+							     TRUE, pScreen, NULL);
+					DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
+						       drmmode_crtc->scanout_damage);
+				}
+
+				pRegion = DamageRegion(drmmode_crtc->scanout_damage);
+				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, drmmode_crtc->mode_crtc->crtc_id,
 				     fb_id, x, y, output_ids, output_count, &kmode);
@@ -1689,7 +1768,7 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 	if (front_bo)
 		radeon_bo_wait(front_bo);
 
-	if (info->allowColorTiling) {
+	if (info->allowColorTiling && !info->shadow_primary) {
 		if (info->ChipFamily >= CHIP_FAMILY_R600) {
 			if (info->allowColorTiling2D) {
 				tiling_flags |= RADEON_TILING_MACRO;
@@ -1770,7 +1849,10 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 	scrn->virtualY = height;
 	scrn->displayWidth = pitch / cpp;
 
-	info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align, RADEON_GEM_DOMAIN_VRAM, 0);
+	info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align,
+					info->shadow_primary ?
+					RADEON_GEM_DOMAIN_GTT :
+					RADEON_GEM_DOMAIN_VRAM, 0);
 	if (!info->front_bo)
 		goto fail;
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 6607896..43a3a4a 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -76,6 +76,7 @@ struct drmmode_scanout {
     struct radeon_bo *bo;
     PixmapPtr pixmap;
     unsigned fb_id;
+    int width, height;
 };
 
 typedef struct {
@@ -84,6 +85,9 @@ typedef struct {
     int hw_id;
     struct radeon_bo *cursor_bo;
     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;
@@ -125,6 +129,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);
 
diff --git a/src/radeon.h b/src/radeon.h
index 80adc5d..afb66b2 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -151,6 +151,7 @@ typedef enum {
     OPTION_SWAPBUFFERS_WAIT,
     OPTION_DELETE_DP12,
     OPTION_DRI3,
+    OPTION_SHADOW_PRIMARY,
 } RADEONOpts;
 
 
@@ -476,6 +477,7 @@ typedef struct {
     struct radeon_accel_state *accel_state;
     Bool              accelOn;
     Bool              use_glamor;
+    Bool              shadow_primary;
     Bool	      exa_pixmaps;
     Bool              exa_force_create;
     XF86ModReqInfo    exaReq;
diff --git a/src/radeon_bo_helper.c b/src/radeon_bo_helper.c
index fdff032..ebbb192 100644
--- a/src/radeon_bo_helper.c
+++ b/src/radeon_bo_helper.c
@@ -88,12 +88,15 @@ radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth,
 	if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH)
 		tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO;
 
+	if ((usage_hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP &&
+	     info->shadow_primary)
 #ifdef CREATE_PIXMAP_USAGE_SHARED
-	if ((usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED) {
+	    || (usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED
+#endif
+	    ) {
 		tiling = 0;
 		domain = RADEON_GEM_DOMAIN_GTT;
 	}
-#endif
     }
 
     /* Small pixmaps must not be macrotiled on R300, hw cannot sample them
diff --git a/src/radeon_dri3.c b/src/radeon_dri3.c
index 3a7322e..1415a0d 100644
--- a/src/radeon_dri3.c
+++ b/src/radeon_dri3.c
@@ -101,8 +101,17 @@ static PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen,
 	if (RADEONPTR(xf86ScreenToScrn(screen))->use_glamor) {
 		pixmap = glamor_pixmap_from_fd(screen, fd, width, height,
 					       stride, depth, bpp);
-		if (pixmap)
-			return pixmap;
+		if (pixmap) {
+			struct radeon_pixmap *priv =
+				calloc(1, sizeof(struct radeon_pixmap));
+
+			if (priv) {
+				radeon_set_pixmap_private(pixmap, priv);
+				return pixmap;
+			}
+
+			screen->DestroyPixmap(pixmap);
+		}
 	}
 #endif
 
@@ -118,7 +127,7 @@ static PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen,
 		return NULL;
 	}
 
-	pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
+	pixmap = screen->CreatePixmap(screen, 0, 0, depth, RADEON_CREATE_PIXMAP_DRI2);
 	if (!pixmap)
 		return NULL;
 
diff --git a/src/radeon_glamor.c b/src/radeon_glamor.c
index 74d9584..eccb8f7 100644
--- a/src/radeon_glamor.c
+++ b/src/radeon_glamor.c
@@ -166,26 +166,24 @@ radeon_glamor_create_textured_pixmap(PixmapPtr pixmap, struct radeon_pixmap *pri
 						 priv->stride);
 }
 
-#ifndef CREATE_PIXMAP_USAGE_SHARED
-#define CREATE_PIXMAP_USAGE_SHARED RADEON_CREATE_PIXMAP_DRI2
-#endif
-
-#define RADEON_CREATE_PIXMAP_SHARED(usage) \
-	(((usage) & ~RADEON_CREATE_PIXMAP_TILING_FLAGS) == RADEON_CREATE_PIXMAP_DRI2 || \
-	 (usage) == CREATE_PIXMAP_USAGE_SHARED)
-
 static PixmapPtr
 radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 			unsigned usage)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	RADEONInfoPtr info = RADEONPTR(scrn);
 	struct radeon_pixmap *priv;
 	PixmapPtr pixmap, new_pixmap = NULL;
 
 	if (!RADEON_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);
+		} else {
+			pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
+			if (pixmap)
+			    return pixmap;
+		}
 	}
 
 	if (w > 32767 || h > 32767)
@@ -220,6 +218,8 @@ radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 
 		if (!radeon_glamor_create_textured_pixmap(pixmap, priv))
 			goto fallback_glamor;
+
+		pixmap->devPrivate.ptr = NULL;
 	}
 
 	return pixmap;
@@ -258,6 +258,13 @@ fallback_pixmap:
 static Bool radeon_glamor_destroy_pixmap(PixmapPtr pixmap)
 {
 	if (pixmap->refcnt == 1) {
+		if (pixmap->devPrivate.ptr) {
+			struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap);
+
+			if (bo)
+				radeon_bo_unmap(bo);
+		}
+
 		glamor_egl_destroy_textured_pixmap(pixmap);
 		radeon_set_pixmap_bo(pixmap, NULL);
 	}
@@ -316,6 +323,26 @@ Bool
 radeon_glamor_init(ScreenPtr screen)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	RADEONInfoPtr info = RADEONPTR(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 |
@@ -338,6 +365,17 @@ radeon_glamor_init(ScreenPtr screen)
 #endif
 		return FALSE;
 
+	if (info->shadow_primary)
+		radeon_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 = radeon_glamor_create_pixmap;
 	screen->DestroyPixmap = radeon_glamor_destroy_pixmap;
 #ifdef RADEON_PIXMAP_SHARING
diff --git a/src/radeon_glamor.h b/src/radeon_glamor.h
index ea385c7..1ba7049 100644
--- a/src/radeon_glamor.h
+++ b/src/radeon_glamor.h
@@ -35,6 +35,16 @@
 
 #include "radeon_surface.h"
 
+#ifndef CREATE_PIXMAP_USAGE_SHARED
+#define CREATE_PIXMAP_USAGE_SHARED RADEON_CREATE_PIXMAP_DRI2
+#endif
+
+#define RADEON_CREATE_PIXMAP_SHARED(usage) \
+	(((usage) & ~RADEON_CREATE_PIXMAP_TILING_FLAGS) == RADEON_CREATE_PIXMAP_DRI2 || \
+	 (usage) == CREATE_PIXMAP_USAGE_SHARED)
+
+struct radeon_pixmap;
+
 #ifndef GLAMOR_NO_DRI3
 #define GLAMOR_NO_DRI3 0
 #define glamor_fd_from_pixmap glamor_dri3_fd_from_pixmap
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 3f723d5..64593ab 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -70,6 +70,7 @@ const OptionInfoRec RADEONOptions_KMS[] = {
     { OPTION_SUBPIXEL_ORDER, "SubPixelOrder",    OPTV_ANYSTR,  {0}, FALSE },
 #ifdef USE_GLAMOR
     { OPTION_ACCELMETHOD,    "AccelMethod",      OPTV_STRING,  {0}, FALSE },
+    { OPTION_SHADOW_PRIMARY, "ShadowPrimary",    OPTV_BOOLEAN, {0}, FALSE },
 #endif
     { OPTION_EXA_VSYNC,      "EXAVSync",         OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_EXA_PIXMAPS,    "EXAPixmaps",	 OPTV_BOOLEAN,   {0}, FALSE },
@@ -308,6 +309,142 @@ radeon_dirty_update(ScreenPtr screen)
 }
 #endif
 
+static Bool
+radeon_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
+radeon_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
+radeon_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;
+    RADEONInfoPtr info;
+    Bool force;
+
+    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 (!radeon_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);
+    info = RADEONPTR(scrn);
+    force = info->accel_state->force;
+    info->accel_state->force = TRUE;
+
+    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);
+
+    info->accel_state->force = force;
+
+    radeon_cs_flush_indirect(scrn);
+
+clear_damage:
+    RegionEmpty(pRegion);
+
+out:
+    drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+radeon_scanout_update(xf86CrtcPtr xf86_crtc)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+    struct radeon_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 (!radeon_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
+					  pDraw->width, pDraw->height))
+	return;
+
+    scrn = xf86_crtc->scrn;
+    drm_queue_entry = radeon_drm_queue_alloc(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT,
+					     RADEON_DRM_QUEUE_ID_DEFAULT,
+					     xf86_crtc,
+					     radeon_scanout_update_handler,
+					     radeon_scanout_update_abort);
+    if (!drm_queue_entry) {
+	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		   "radeon_drm_queue_alloc failed for scanout update\n");
+	return;
+    }
+
+    vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
+    vbl.request.type |= radeon_populate_vbl_request_type(xf86_crtc);
+    vbl.request.sequence = 1;
+    vbl.request.signal = (unsigned long)drm_queue_entry;
+    if (drmWaitVBlank(RADEONPTR(scrn)->dri2.drm_fd, &vbl)) {
+	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		   "drmWaitVBlank failed for scanout update: %s\n",
+		   strerror(errno));
+	radeon_drm_abort_entry(drm_queue_entry);
+	return;
+    }
+
+    drmmode_crtc->scanout_update_pending = TRUE;
+}
+
 static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
 {
     SCREEN_PTR(arg);
@@ -318,7 +455,16 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
     (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
     pScreen->BlockHandler = RADEONBlockHandler_KMS;
 
+    if (info->shadow_primary) {
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+	int c;
+
+	for (c = 0; c < xf86_config->num_crtc; c++)
+	    radeon_scanout_update(xf86_config->crtc[c]);
+    }
+
     radeon_cs_flush_indirect(pScrn);
+
 #ifdef RADEON_PIXMAP_SHARING
     radeon_dirty_update(pScreen);
 #endif
@@ -936,11 +1082,32 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 	 "KMS Color Tiling 2D: %sabled\n", info->allowColorTiling2D ? "en" : "dis");
 
+#if USE_GLAMOR
+    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");
+    }
+#endif
+
     if (info->dri2.pKernelDRMVersion->version_minor >= 8) {
 	info->allowPageFlip = xf86ReturnOptValBool(info->Options,
 						   OPTION_PAGE_FLIP, TRUE);
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-		   "KMS Pageflipping: %sabled\n", info->allowPageFlip ? "en" : "dis");
+#if USE_GLAMOR
+	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
+#endif
+	{
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "KMS Pageflipping: %sabled\n", info->allowPageFlip ? "en" : "dis");
+	}
     }
 
     info->swapBuffersWait = xf86ReturnOptValBool(info->Options,
@@ -1506,6 +1673,7 @@ void RADEONLeaveVT_KMS(VT_FUNC_ARGS_DECL)
     radeon_drop_drm_master(pScrn);
 
     xf86RotateFreeShadow(pScrn);
+    drmmode_scanout_free(pScrn);
 
     xf86_hide_cursors (pScrn);
     info->accel_state->XInited3D = FALSE;
@@ -1556,7 +1724,7 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen)
 	}
     }
 
-    if (info->allowColorTiling) {
+    if (info->allowColorTiling && !info->shadow_primary) {
 	if (info->ChipFamily >= CHIP_FAMILY_R600) {
 		if (info->allowColorTiling2D) {
 			tiling_flags |= RADEON_TILING_MACRO;
@@ -1659,7 +1827,10 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen)
 
     if (info->front_bo == NULL) {
         info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size,
-                                        base_align, RADEON_GEM_DOMAIN_VRAM, 0);
+                                        base_align,
+                                        info->shadow_primary ?
+                                        RADEON_GEM_DOMAIN_GTT :
+                                        RADEON_GEM_DOMAIN_VRAM, 0);
         if (info->r600_shadow_fb == TRUE) {
             if (radeon_bo_map(info->front_bo, 1)) {
                 ErrorF("Failed to map cursor buffer memory\n");
-- 
2.1.4



More information about the xorg-driver-ati mailing list