/* * Queue a flip back to the normal frame buffer */ static void intel_present_unflip(ScreenPtr screen, uint64_t event_id) { ScrnInfoPtr scrn = xf86ScreenToScrn(screen); intel_screen_private *intel = intel_get_screen_private(scrn); PixmapPtr pixmap = screen->GetScreenPixmap(screen); struct intel_present_vblank_event *event = NULL; dri_bo *bo; if (!intel_present_check_flip(NULL, screen->root, pixmap, true)) goto fail; bo = intel_get_pixmap_bo(pixmap); if (!bo) goto fail; event = calloc(1, sizeof(struct intel_present_vblank_event)); if (!event) goto fail; event->event_id = event_id; if (!intel_do_pageflip(intel, bo, -1, FALSE, event, intel_present_flip_event, intel_present_flip_abort)) goto fail; return; fail: xf86SetDesiredModes(scrn); present_event_notify(event_id, 0, 0); free(event); }
static void sna_present_unflip(ScreenPtr screen, uint64_t event_id) { struct sna *sna = to_sna_from_screen(screen); struct kgem_bo *bo; DBG(("%s(event=%lld)\n", __FUNCTION__, (long long)event_id)); if (sna->mode.front_active == 0 || sna->mode.shadow_active) { const struct ust_msc *swap; DBG(("%s: no CRTC active, perform no-op flip\n", __FUNCTION__)); notify: swap = sna_crtc_last_swap(sna_mode_first_crtc(sna)); DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, event %lld complete\n", __FUNCTION__, -1, swap->tv_sec, swap->tv_usec, (long long)swap->msc, (long long)event_id)); present_event_notify(event_id, ust64(swap->tv_sec, swap->tv_usec), swap->msc); return; } bo = get_flip_bo(screen->GetScreenPixmap(screen)); if (bo == NULL || !page_flip(screen, NULL, event_id, bo)) { DBG(("%s: failed, trying to restore original mode\n", __FUNCTION__)); xf86SetDesiredModes(sna->scrn); goto notify; } }
static Bool page_flip__async(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, struct kgem_bo *bo) { DBG(("%s(pipe=%d, event=%lld, handle=%d)\n", __FUNCTION__, pipe_from_crtc(crtc), (long long)event_id, bo->handle)); if (!sna_page_flip(to_sna_from_screen(crtc->pScreen), bo, NULL, NULL)) { DBG(("%s: async pageflip failed\n", __FUNCTION__)); present_info.capabilities &= ~PresentCapabilityAsync; return FALSE; } DBG(("%s: pipe=%d tv=%d.%06d msc=%d, event %lld complete\n", __FUNCTION__, pipe_from_crtc(crtc), gettime_ust64() / 1000000, gettime_ust64() % 1000000, sna_crtc_last_swap(crtc->devPrivate)->msc, (long long)event_id)); present_event_notify(event_id, gettime_ust64(), target_msc); return TRUE; }
/* * Once the flip has been completed on all pipes, notify the * extension code telling it when that happened */ static void intel_present_flip_event(uint64_t msc, uint64_t ust, void *pageflip_data) { struct intel_present_vblank_event *event = pageflip_data; present_event_notify(event->event_id, ust, msc); free(event); }
/* * Called when the queued vblank event has occurred */ static void intel_present_vblank_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t msc, uint64_t usec, void *data) { struct intel_present_vblank_event *event = data; present_event_notify(event->event_id, usec, msc); free(event); }
static void nouveau_present_vblank(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo) { struct nouveau_present_vblank *event = priv; uint64_t msc; msc = (event->msc & 0xffffffff00000000ULL) | msc_lo; if (msc < event->msc) event->msc += 1ULL << 32; present_event_notify(name, ust, msc); }
static void nouveau_present_flip(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo) { struct nouveau_present_flip *flip = priv; uint64_t msc; msc = (flip->msc & ~0xffffffffULL) | msc_lo; if (msc < flip->msc) msc += 1ULL << 32; present_event_notify(name, ust, msc); drmModeRmFB(flip->fd, flip->old); }
void sna_present_vblank_handler(struct sna *sna, struct drm_event_vblank *event) { struct sna_present_event *info = to_present_event(event->user_data); DBG(("%s: pipe=%d event=%lld, tv=%d.%06d msc=%d\n", __FUNCTION__, sna_crtc_to_pipe(info->crtc), (long long)info->event_id, event->tv_sec, event->tv_usec, event->sequence)); present_event_notify(info->event_id, ust64(event->tv_sec, event->tv_usec), sna_crtc_record_event(info->crtc, event)); free(info); }
/* * Queue a flip back to the normal frame buffer */ static void ms_present_unflip(ScreenPtr screen, uint64_t event_id) { ScrnInfoPtr scrn = xf86ScreenToScrn(screen); PixmapPtr pixmap = screen->GetScreenPixmap(screen); xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); int i; struct ms_present_vblank_event *event; event = calloc(1, sizeof(struct ms_present_vblank_event)); if (!event) return; event->event_id = event_id; if (ms_present_check_flip(NULL, screen->root, pixmap, TRUE) && ms_do_pageflip(screen, pixmap, event, -1, FALSE)) { return; } for (i = 0; i < config->num_crtc; i++) { xf86CrtcPtr crtc = config->crtc[i]; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; if (!crtc->enabled) continue; /* info->drmmode.fb_id still points to the FB for the last flipped BO. * Clear it, drmmode_set_mode_major will re-create it */ if (drmmode_crtc->drmmode->fb_id) { drmModeRmFB(drmmode_crtc->drmmode->fd, drmmode_crtc->drmmode->fb_id); drmmode_crtc->drmmode->fb_id = 0; } if (drmmode_crtc->dpms_mode == DPMSModeOn) crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y); else drmmode_crtc->need_modeset = TRUE; } present_event_notify(event_id, 0, 0); }
static void present_flip_handler(struct drm_event_vblank *event, void *data) { struct sna_present_event *info = data; struct ust_msc swap; DBG(("%s(sequence=%d)\n", __FUNCTION__, event->sequence)); if (info->crtc == NULL) { swap.tv_sec = event->tv_sec; swap.tv_usec = event->tv_usec; swap.msc = event->sequence; } else swap = *sna_crtc_last_swap(info->crtc); DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, event %lld complete\n", __FUNCTION__, info->crtc ? sna_crtc_to_pipe(info->crtc) : -1, swap.tv_sec, swap.tv_usec, (long long)swap.msc, (long long)info->event_id)); present_event_notify(info->event_id, ust64(swap.tv_sec, swap.tv_usec), swap.msc); free(info); }
/* * Flush the DRM event queue when full; makes space for new events. * * Returns a negative value on error, 0 if there was nothing to process, * or 1 if we handled any events. */ static int ms_flush_drm_events(ScreenPtr screen) { ScrnInfoPtr scrn = xf86ScreenToScrn(screen); modesettingPtr ms = modesettingPTR(scrn); struct pollfd p = { .fd = ms->fd, .events = POLLIN }; int r; do { r = poll(&p, 1, 0); } while (r == -1 && (errno == EINTR || errno == EAGAIN)); /* If there was an error, r will be < 0. Return that. If there was * nothing to process, r == 0. Return that. */ if (r <= 0) return r; /* Try to handle the event. If there was an error, return it. */ r = drmHandleEvent(ms->fd, &ms->event_context); if (r < 0) return r; /* Otherwise return 1 to indicate that we handled an event. */ return 1; } /* * Called when the queued vblank event has occurred */ static void ms_present_vblank_handler(uint64_t msc, uint64_t usec, void *data) { struct ms_present_vblank_event *event = data; DebugPresent(("\t\tmh %lld msc %llu\n", (long long) event->event_id, (long long) msc)); present_event_notify(event->event_id, usec, msc); free(event); } /* * Called when the queued vblank is aborted */ static void ms_present_vblank_abort(void *data) { struct ms_present_vblank_event *event = data; DebugPresent(("\t\tma %lld\n", (long long) event->event_id)); free(event); } /* * Queue an event to report back to the Present extension when the specified * MSC has past */ static int ms_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) { xf86CrtcPtr xf86_crtc = crtc->devPrivate; ScreenPtr screen = crtc->pScreen; ScrnInfoPtr scrn = xf86ScreenToScrn(screen); modesettingPtr ms = modesettingPTR(scrn); drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; struct ms_present_vblank_event *event; drmVBlank vbl; int ret; uint32_t seq; event = calloc(sizeof(struct ms_present_vblank_event), 1); if (!event) return BadAlloc; event->event_id = event_id; seq = ms_drm_queue_alloc(xf86_crtc, event, ms_present_vblank_handler, ms_present_vblank_abort); if (!seq) { free(event); return BadAlloc; } vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | drmmode_crtc->vblank_pipe; vbl.request.sequence = ms_crtc_msc_to_kernel_msc(xf86_crtc, msc); vbl.request.signal = seq; for (;;) { ret = drmWaitVBlank(ms->fd, &vbl); if (!ret) break; /* If we hit EBUSY, then try to flush events. If we can't, then * this is an error. */ if (errno != EBUSY || ms_flush_drm_events(screen) < 0) { ms_drm_abort_seq(scrn, seq); return BadAlloc; } } DebugPresent(("\t\tmq %lld seq %u msc %llu (hw msc %u)\n", (long long) event_id, seq, (long long) msc, vbl.request.sequence)); return Success; }