void vivante_dri2_vblank(int fd, unsigned frame, unsigned tv_sec, unsigned tv_usec, void *event) { struct vivante_dri_wait *wait = event; DrawablePtr draw; if (!wait->drawable_id) goto out; if (dixLookupDrawable(&draw, wait->drawable_id, serverClient, M_ANY, DixWriteAccess) != Success) goto out; switch (wait->type) { case DRI2_FLIP: if (can_exchange(draw, wait->front, wait->back) && vivante_dri2_ScheduleFlip(draw, wait)) return; /* FALLTHROUGH */ case DRI2_SWAP: vivante_dri2_blit(wait->client, draw, wait->front, wait->back, frame, tv_sec, tv_usec, wait->client ? wait->event_func : NULL, wait->event_data); break; case DRI2_WAITMSC: if (wait->client) DRI2WaitMSCComplete(wait->client, draw, frame, tv_sec, tv_usec); break; default: xf86DrvMsg(xf86ScreenToScrn(draw->pScreen)->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __FUNCTION__); break; } out: del_wait_info(wait); }
static void nouveau_dri2_vblank_handler(void *priv, uint64_t name, uint64_t ust, uint32_t frame) { struct dri2_vblank *event = priv; struct nouveau_dri2_vblank_state *s = event->s; uint32_t tv_sec = ust / 1000000; uint32_t tv_usec = ust % 1000000; DrawablePtr draw; int ret; ret = dixLookupDrawable(&draw, s->draw, serverClient, M_ANY, DixWriteAccess); if (ret) { free(s); return; } switch (s->action) { case SWAP: nouveau_dri2_finish_swap(draw, frame, tv_sec, tv_usec, s); #if DRI2INFOREC_VERSION >= 6 /* Restore real swap limit on drawable, now that it is safe. */ ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); DRI2SwapLimit(draw, NVPTR(scrn)->swap_limit); #endif break; case WAIT: DRI2WaitMSCComplete(s->client, draw, frame, tv_sec, tv_usec); free(s); break; case BLIT: DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec, DRI2_BLIT_COMPLETE, s->func, s->data); free(s); break; } }
static int vivante_dri2_ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, CARD64 divisor, CARD64 remainder) { struct vivante *vivante = vivante_get_screen_priv(draw->pScreen); struct vivante_dri_wait *wait; drmVBlank vbl; int ret, crtc; CARD64 cur_msc; target_msc &= 0xffffffff; divisor &= 0xffffffff; remainder &= 0xffffffff; crtc = vivante_dri2_drawable_crtc(draw); /* Drawable not displayed, just complete */ if (crtc < 0) goto out; wait = new_wait_info(client, draw, DRI2_WAITMSC); if (!wait) goto out; /* Get current count */ ret = vivante_dri2_waitvblank(vivante, &vbl, crtc, __FUNCTION__); if (ret) goto out_free; cur_msc = vbl.reply.sequence; /* * If the divisor is zero, or cur_msc is smaller than target_msc, we * just need to make sure target_msc passes before waking up the client. */ if (divisor == 0 || cur_msc < target_msc) { if (cur_msc >= target_msc) target_msc = cur_msc; vbl.request.sequence = target_msc; } else { /* * If we get here, target_msc has already passed or we * don't have one, so queue an event that will satisfy * the divisor/remainder equation. */ vbl.request.sequence = cur_msc - (cur_msc % divisor) + remainder; /* * If calculated remainder is larger than requested * remainder, it means we've passed the point where * seq % divisor == remainder, so we need to wait for * the next time that will happen. */ if ((cur_msc & divisor) >= remainder) vbl.request.sequence += divisor; } vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | drm_req_crtc(crtc); vbl.request.signal = (unsigned long)wait; ret = drmWaitVBlank(vivante->drm_fd, &vbl); if (ret) { xf86DrvMsg(vivante->scrnIndex, X_WARNING, "%s: get vblank counter failed: %s\n", __FUNCTION__, strerror(errno)); goto out_free; } wait->frame = vbl.reply.sequence; DRI2BlockClient(client, draw); return TRUE; out_free: del_wait_info(wait); out: DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); return TRUE; }