[PATCH xf86-video-ati 2/2] kms: Move flip_count and co. to a per swap structure

Ville Syrjala syrjala at sci.fi
Wed May 4 13:51:27 PDT 2011


If multiple drawables are doing page flipping, the global drmmode
structure can't be used to keep per swap information. For example
flip_count can increase prematurely due to another swap request,
and then the previous swap request never gets completed, leading to a
stuck client. Move the relevant pieces of data to a strucuture that
gets allocated once per swap request and shared by all involved CRTCs.

Signed-off-by: Ville Syrjala <syrjala at sci.fi>
---
 src/drmmode_display.c |   45 ++++++++++++++++++++++++++-------------------
 src/drmmode_display.h |   10 +++++++---
 2 files changed, 33 insertions(+), 22 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 7873d57..7dd5d86 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1331,31 +1331,34 @@ drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
 		     unsigned int tv_usec, void *event_data)
 {
 	drmmode_flipevtcarrier_ptr flipcarrier = event_data;
-	drmmode_ptr drmmode = flipcarrier->drmmode;
+	drmmode_flipdata_ptr flipdata = flipcarrier->flipdata;
+	drmmode_ptr drmmode = flipdata->drmmode;
 
 	/* Is this the event whose info shall be delivered to higher level? */
 	if (flipcarrier->dispatch_me) {
 		/* Yes: Cache msc, ust for later delivery. */
-		drmmode->fe_frame = frame;
-		drmmode->fe_tv_sec = tv_sec;
-		drmmode->fe_tv_usec = tv_usec;
+		flipdata->fe_frame = frame;
+		flipdata->fe_tv_sec = tv_sec;
+		flipdata->fe_tv_usec = tv_usec;
 	}
 	free(flipcarrier);
 
 	/* Last crtc completed flip? */
-	drmmode->flip_count--;
-	if (drmmode->flip_count > 0)
+	flipdata->flip_count--;
+	if (flipdata->flip_count > 0)
 		return;
 
 	/* Release framebuffer */
-	drmModeRmFB(drmmode->fd, drmmode->old_fb_id);
+	drmModeRmFB(drmmode->fd, flipdata->old_fb_id);
 
-	if (drmmode->event_data == NULL)
+	if (flipdata->event_data == NULL)
 		return;
 
 	/* Deliver cached msc, ust from reference crtc to flip event handler */
-	radeon_dri2_flip_event_handler(drmmode->fe_frame, drmmode->fe_tv_sec,
-				       drmmode->fe_tv_usec, drmmode->event_data);
+	radeon_dri2_flip_event_handler(flipdata->fe_frame, flipdata->fe_tv_sec,
+				       flipdata->fe_tv_usec, flipdata->event_data);
+
+	free(flipdata);
 }
 
 
@@ -1399,12 +1402,10 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
 
 	xf86InitialConfiguration(pScrn, TRUE);
 
-	drmmode->flip_count = 0;
 	drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
 	drmmode->event_context.vblank_handler = drmmode_vblank_handler;
 	drmmode->event_context.page_flip_handler = drmmode_flip_handler;
 	if (!pRADEONEnt->fd_wakeup_registered && info->dri->pKernelDRMVersion->version_minor >= 4) {
-		drmmode->flip_count = 0;
 		AddGeneralSocket(drmmode->fd);
 		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
 				drm_wakeup_handler, drmmode);
@@ -1654,6 +1655,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
 	int i, old_fb_id;
 	uint32_t tiling_flags = 0;
 	int height;
+	drmmode_flipdata_ptr flipdata;
 	drmmode_flipevtcarrier_ptr flipcarrier;
 
 	if (info->allowColorTiling) {
@@ -1676,6 +1678,12 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
 			 new_front->handle, &drmmode->fb_id))
 		goto error_out;
 
+        flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
+        if (!flipdata) {
+             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+                        "flip queue: data alloc failed.\n");
+             goto error_undo;
+        }
 	/*
 	 * Queue flips on all enabled CRTCs
 	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
@@ -1685,16 +1693,15 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
 	 * Also, flips queued on disabled or incorrectly configured displays
 	 * may never complete; this is a configuration error.
 	 */
-	drmmode->fe_frame = 0;
-	drmmode->fe_tv_sec = 0;
-	drmmode->fe_tv_usec = 0;
+
+        flipdata->event_data = data;
+        flipdata->drmmode = drmmode;
 
 	for (i = 0; i < config->num_crtc; i++) {
 		if (!config->crtc[i]->enabled)
 			continue;
 
-		drmmode->event_data = data;
-		drmmode->flip_count++;
+		flipdata->flip_count++;
 		drmmode_crtc = config->crtc[i]->driver_private;
 
 		flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec));
@@ -1708,7 +1715,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
 		 * completion event. All other crtc's events will be discarded.
 		 */
 		flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id);
-		flipcarrier->drmmode = drmmode;
+		flipcarrier->flipdata = flipdata;
 
 		if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
 				    drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) {
@@ -1719,7 +1726,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
 		}
 	}
 
-	drmmode->old_fb_id = old_fb_id;
+	flipdata->old_fb_id = old_fb_id;
 	return TRUE;
 
 error_undo:
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 548907b..eb271f5 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -39,7 +39,6 @@
 typedef struct {
   int fd;
   unsigned fb_id;
-  unsigned old_fb_id;
   drmModeResPtr mode_res;
   drmModeFBPtr mode_fb;
   int cpp;
@@ -50,15 +49,20 @@ typedef struct {
   InputHandlerProc uevent_handler;
 #endif
   drmEventContext event_context;
+} drmmode_rec, *drmmode_ptr;
+
+typedef struct {
+  drmmode_ptr drmmode;
+  unsigned old_fb_id;
   int flip_count;
   void *event_data;
   unsigned int fe_frame;
   unsigned int fe_tv_sec;
   unsigned int fe_tv_usec;
-} drmmode_rec, *drmmode_ptr;
+} drmmode_flipdata_rec, *drmmode_flipdata_ptr;
 
 typedef struct {
-  drmmode_ptr drmmode;
+  drmmode_flipdata_ptr flipdata;
   Bool dispatch_me;
 } drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr;
 
-- 
1.7.3.4



More information about the xorg-devel mailing list