From 1dda08cf36eef054adc875cf28e20b085ee66f02 Mon Sep 17 00:00:00 2001 From: Alban Browaeys Date: Tue, 24 Aug 2010 08:22:05 +0200 Subject: [PATCH] radeon: better fix for vblank and clientGone. --- src/radeon_dri2.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 157 insertions(+), 5 deletions(-) diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c index a0ed085..4e18db1 100644 --- a/src/radeon_dri2.c +++ b/src/radeon_dri2.c @@ -58,6 +58,113 @@ struct dri2_buffer_priv { }; +typedef struct _DRI2ClientProcessEvent { + // Identitifiers + int client_index; + TimeStamp eventTimeStamp; + + // Facilities. + ClientPtr client; +} DRI2ClientProcessEventRec, *DRI2ClientProcessEventPtr; + +typedef struct ClientProcessEventList { + DRI2ClientProcessEventPtr clientProcessEvent; + Bool valid; + struct ClientProcessEventList *next; +} ClientProcessEventList; + +static ClientProcessEventList *clientProcessEventList = NULL; + + +static DRI2ClientProcessEventPtr +AddClientProcessEvent(ClientPtr client, TimeStamp eventTime) +{ + ClientProcessEventList *l; + DRI2ClientProcessEventPtr c; + + c = malloc(sizeof(DRI2ClientProcessEventRec)); + c->client_index = client->index; + c->client = client; + c->eventTimeStamp = eventTime; + + l = malloc(sizeof(ClientProcessEventList)); + l->clientProcessEvent = c; + l->valid = TRUE; + l->next = clientProcessEventList; + clientProcessEventList = l; + + return c; +} + +static void +RemoveClientProcessEvent(DRI2ClientProcessEventPtr clientProcessEvent) +{ + ClientProcessEventList *l, *p; + + if ((clientProcessEventList->clientProcessEvent->client_index == clientProcessEvent->client_index) + && (!CompareTimeStamps(clientProcessEventList->clientProcessEvent->eventTimeStamp, clientProcessEvent->eventTimeStamp))) { + l = clientProcessEventList; + clientProcessEventList = l->next; + free(l->clientProcessEvent); + free(l); + } else { + p = clientProcessEventList; + for (l = clientProcessEventList->next; l != NULL; l = l->next) { + if ((l->clientProcessEvent->client_index == clientProcessEvent->client_index) + && (!CompareTimeStamps(l->clientProcessEvent->eventTimeStamp , clientProcessEvent->eventTimeStamp))) { + p->next = l->next; + free(l->clientProcessEvent); + free(l); + break; + } + p = l; + } + } + +} + +static void +InvalidateClientProcessEvent(ClientPtr client) +{ + ClientProcessEventList *l; + + for (l = clientProcessEventList; l != NULL; l = l->next) { + if (l->clientProcessEvent->client_index == client->index) { + l->valid = FALSE; + } + } + +} + +static Bool +IsValidClientProcessEvent(DRI2ClientProcessEventPtr clientProcessEvent) +{ + ClientProcessEventList *l; + + for (l = clientProcessEventList; l != NULL; l = l->next) { + if (l->valid) + return TRUE; + } + + return FALSE; +} + +static void +FreeClientProcessEventList() +{ + ClientProcessEventList *l, *p; + + p = clientProcessEventList; + for (l = clientProcessEventList; l != NULL; l = l->next) { + p->next = l->next; + free(l->clientProcessEvent); + free(l); + p = l; + } + +} + + #ifndef USE_DRI2_1_1_0 static BufferPtr radeon_dri2_create_buffers(DrawablePtr drawable, @@ -329,6 +436,8 @@ radeon_dri2_copy_region(DrawablePtr drawable, #if DRI2INFOREC_VERSION >= 4 +CallbackListPtr ClientStateCallback; + enum DRI2FrameEventType { DRI2_SWAP, DRI2_FLIP, @@ -337,7 +446,7 @@ enum DRI2FrameEventType { typedef struct _DRI2FrameEvent { XID drawable_id; - ClientPtr client; + DRI2ClientProcessEventPtr clientProcessEvent; enum DRI2FrameEventType type; int frame; @@ -348,6 +457,28 @@ typedef struct _DRI2FrameEvent { DRI2BufferPtr back; } DRI2FrameEventRec, *DRI2FrameEventPtr; + + +void radeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata) +{ + + NewClientInfoRec *pci = calldata; + + switch (pci->client->clientState) { + case ClientStateInitial: + case ClientStateRunning: + case ClientStateRetained: + break; + + case ClientStateGone: + InvalidateClientProcessEvent(pci->client); + break; + default: + break; + } +} + + void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, void *event_data) { @@ -355,11 +486,21 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, DrawablePtr drawable; ScreenPtr screen; ScrnInfoPtr scrn; + ClientPtr client; int status; int swap_type; BoxRec box; RegionRec region; + if (!IsValidClientProcessEvent(event->clientProcessEvent)) { + RemoveClientProcessEvent(event->clientProcessEvent); + free(event); + return; + } + + + client = event->clientProcessEvent->client; + status = dixLookupDrawable(&drawable, event->drawable_id, serverClient, M_ANY, DixWriteAccess); if (status != Success) { @@ -381,11 +522,11 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, radeon_dri2_copy_region(drawable, ®ion, event->front, event->back); swap_type = DRI2_BLIT_COMPLETE; - DRI2SwapComplete(event->client, drawable, frame, tv_sec, tv_usec, + DRI2SwapComplete(client, drawable, frame, tv_sec, tv_usec, swap_type, event->event_complete, event->event_data); break; case DRI2_WAITMSC: - DRI2WaitMSCComplete(event->client, drawable, frame, tv_sec, tv_usec); + DRI2WaitMSCComplete(client, drawable, frame, tv_sec, tv_usec); break; default: /* Unknown type */ @@ -394,6 +535,7 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, break; } + RemoveClientProcessEvent(event->clientProcessEvent); free(event); } @@ -471,6 +613,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, drmVBlank vbl; int ret, crtc = radeon_dri2_drawable_crtc(draw); CARD64 current_msc; + DRI2ClientProcessEventPtr clientProcessEvent; /* Truncate to match kernel interfaces; means occasional overflow * misses, but that's generally not a big deal */ @@ -486,8 +629,9 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, if (!wait_info) goto out_complete; + clientProcessEvent = AddClientProcessEvent(client, currentTime); wait_info->drawable_id = draw->id; - wait_info->client = client; + wait_info->clientProcessEvent = clientProcessEvent; wait_info->type = DRI2_WAITMSC; /* Get current count */ @@ -609,6 +753,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, CARD64 current_msc; BoxRec box; RegionRec region; + DRI2ClientProcessEventPtr clientProcessEvent; /* Truncate to match kernel interfaces; means occasional overflow * misses, but that's generally not a big deal */ @@ -622,8 +767,9 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, if (crtc == -1 || !swap_info) goto blit_fallback; + clientProcessEvent = AddClientProcessEvent(client, currentTime); swap_info->drawable_id = draw->id; - swap_info->client = client; + swap_info->clientProcessEvent = clientProcessEvent; swap_info->event_complete = func; swap_info->event_data = data; swap_info->front = front; @@ -810,6 +956,8 @@ radeon_dri2_screen_init(ScreenPtr pScreen) } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for sync extension\n"); } + + AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); #endif info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info); @@ -821,6 +969,10 @@ 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 + FreeClientProcessEventList(); DRI2CloseScreen(pScreen); drmFree(info->dri2.device_name); } -- 1.7.1