From 80b722731b23898c9c0e393af9228886dca603bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Old=C5=99ich=20Jedli=C4=8Dka?= Date: Mon, 6 Sep 2010 21:14:52 +0200 Subject: [PATCH] radeon: vblank when client gone event version. (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v1 (Alban Browaeys): Based upon a detailed explanation from Oldřich Jedlička and comments from Christopher James Halse Rogers. on http://lists.x.org/archives/xorg-driver-ati/2010-August/016780.html . v2: Updated version to apply on master. Removed unnecessary client_index field from _DRI2FrameEvent. Added freeing/removing from list to failed paths of radeon_dri2_schedule_wait_msc and radeon_dri2_schedule_swap. --- src/radeon_dri2.c | 132 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 111 insertions(+), 21 deletions(-) diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c index ed7fdd6..7e57cf8 100644 --- a/src/radeon_dri2.c +++ b/src/radeon_dri2.c @@ -37,6 +37,7 @@ #include "radeon.h" #include "radeon_dri2.h" #include "radeon_version.h" +#include "list.h" #ifdef RADEON_DRI2 @@ -376,7 +377,6 @@ enum DRI2FrameEventType { typedef struct _DRI2FrameEvent { XID drawable_id; ClientPtr client; - int client_index; enum DRI2FrameEventType type; int frame; @@ -385,8 +385,77 @@ typedef struct _DRI2FrameEvent { void *event_data; DRI2BufferPtr front; DRI2BufferPtr back; + + Bool valid; + + struct list link; } DRI2FrameEventRec, *DRI2FrameEventPtr; +typedef struct _DRI2ClientEvents { + struct list reference_list; +} DRI2ClientEventsRec, *DRI2ClientEventsPtr; + +static DevPrivateKeyRec DRI2ClientEventsPrivateKeyRec; +#define DRI2ClientEventsPrivateKey (&DRI2ClientEventsPrivateKeyRec) + +#define GetDRI2ClientEvents(_pClient) (DRI2ClientEventsPtr) \ + dixLookupPrivate(&(_pClient)->devPrivates, DRI2ClientEventsPrivateKey) + +static int +ListAddDRI2ClientEvents(ClientPtr client, struct list *entry) +{ + DRI2ClientEventsPtr pClientPriv; + pClientPriv = GetDRI2ClientEvents(client); + + if (!pClientPriv) { + return BadAlloc; + } + + list_add(entry, &pClientPriv->reference_list); + return 0; +} + +static void +ListDelDRI2ClientEvents(ClientPtr client, struct list *entry) +{ + DRI2ClientEventsPtr pClientPriv; + pClientPriv = GetDRI2ClientEvents(client); + + if (!pClientPriv) { + return; + } + list_del(entry); +} + +static void +radeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata) +{ + DRI2ClientEventsPtr pClientEventsPriv; + DRI2FrameEventPtr ref; + NewClientInfoRec *clientinfo = calldata; + ClientPtr pClient = clientinfo->client; + pClientEventsPriv = GetDRI2ClientEvents(pClient); + + switch (pClient->clientState) { + case ClientStateInitial: + list_init(&pClientEventsPriv->reference_list); + break; + case ClientStateRunning: + break; + + case ClientStateRetained: + case ClientStateGone: + if (pClientEventsPriv) { + list_for_each_entry(ref, &pClientEventsPriv->reference_list, link) { + ref->valid = FALSE; + } + } + break; + default: + break; + } +} + static void radeon_dri2_ref_buffer(BufferPtr buffer) { @@ -416,28 +485,20 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, BoxRec box; RegionRec region; + if (!event->valid) { + goto cleanup; + } + status = dixLookupDrawable(&drawable, event->drawable_id, serverClient, M_ANY, DixWriteAccess); if (status != Success) { - radeon_dri2_unref_buffer(event->front); - radeon_dri2_unref_buffer(event->back); - free(event); + goto cleanup; return; } screen = drawable->pScreen; scrn = xf86Screens[screen->myNum]; - - /* event->client may have quit between submitting a request - * and this callback being triggered. - * - * Check our saved client pointer against the client in the saved client - * slot. This will catch almost all cases where the client that requested - * SwapBuffers has gone away, and will guarantee that there is at least a - * valid client to write the BufferSwapComplete event to. - */ - client = event->client == clients[event->client_index] ? - event->client : NULL; + client = event->client; switch (event->type) { case DRI2_FLIP: @@ -453,8 +514,6 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, DRI2SwapComplete(client, drawable, frame, tv_sec, tv_usec, swap_type, event->event_complete, event->event_data); - radeon_dri2_unref_buffer(event->front); - radeon_dri2_unref_buffer(event->back); break; case DRI2_WAITMSC: DRI2WaitMSCComplete(client, drawable, frame, tv_sec, tv_usec); @@ -466,6 +525,11 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, break; } +cleanup: + radeon_dri2_unref_buffer(event->front); + radeon_dri2_unref_buffer(event->back); + if (event->valid) + ListDelDRI2ClientEvents(event->client, &event->link); free(event); } @@ -539,7 +603,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, ScreenPtr screen = draw->pScreen; ScrnInfoPtr scrn = xf86Screens[screen->myNum]; RADEONInfoPtr info = RADEONPTR(scrn); - DRI2FrameEventPtr wait_info; + DRI2FrameEventPtr wait_info = NULL; drmVBlank vbl; int ret, crtc = radeon_dri2_drawable_crtc(draw); CARD64 current_msc; @@ -560,8 +624,14 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, wait_info->drawable_id = draw->id; wait_info->client = client; - wait_info->client_index = client->index; wait_info->type = DRI2_WAITMSC; + wait_info->valid = TRUE; + + if (ListAddDRI2ClientEvents(client, &wait_info->link)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "add events to client private failed.\n"); + goto out_complete; + } /* Get current count */ vbl.request.type = DRM_VBLANK_RELATIVE; @@ -642,6 +712,10 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, return TRUE; out_complete: + if (wait_info) { + ListDelDRI2ClientEvents(wait_info->client, &wait_info->link); + free(wait_info); + } DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); return TRUE; } @@ -704,11 +778,16 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, swap_info->drawable_id = draw->id; swap_info->client = client; - swap_info->client_index = client->index; swap_info->event_complete = func; swap_info->event_data = data; swap_info->front = front; swap_info->back = back; + swap_info->valid = TRUE; + if (ListAddDRI2ClientEvents(client, &swap_info->link)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "add events to client private failed.\n"); + goto blit_fallback; + } /* Get current count */ vbl.request.type = DRM_VBLANK_RELATIVE; @@ -831,8 +910,10 @@ blit_fallback: radeon_dri2_copy_region(draw, ®ion, front, back); DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); - if (swap_info) + if (swap_info) { + ListDelDRI2ClientEvents(swap_info->client, &swap_info->link); free(swap_info); + } radeon_dri2_unref_buffer(front); radeon_dri2_unref_buffer(back); @@ -895,6 +976,12 @@ radeon_dri2_screen_init(ScreenPtr pScreen) } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for sync extension\n"); } + + if (!dixRegisterPrivateKey(DRI2ClientEventsPrivateKey, PRIVATE_CLIENT, sizeof(DRI2ClientEventsRec))) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 registering private key to client failed\n"); + return FALSE; + } + AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); #endif info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info); @@ -906,6 +993,9 @@ void radeon_dri2_close_screen(ScreenPtr pScreen) ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; RADEONInfoPtr info = RADEONPTR(pScrn); +#if DRI2INFOREC_VERSION >= 4 + DeleteCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); +#endif DRI2CloseScreen(pScreen); drmFree(info->dri2.device_name); } -- 1.7.2.2