static void nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, struct nouveau_dri2_vblank_state *s) { ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); NVPtr pNv = NVPTR(scrn); PixmapPtr dst_pix; PixmapPtr src_pix = nouveau_dri2_buffer(s->src)->ppix; struct nouveau_bo *dst_bo; struct nouveau_bo *src_bo = nouveau_pixmap_bo(src_pix); struct nouveau_pushbuf *push = pNv->pushbuf; RegionRec reg; int type, ret; Bool front_updated, will_exchange; xf86CrtcPtr ref_crtc; REGION_INIT(0, ®, (&(BoxRec){ 0, 0, draw->width, draw->height }), 0); REGION_TRANSLATE(0, ®, draw->x, draw->y); /* Main crtc for this drawable shall finally deliver pageflip event. */ ref_crtc = nouveau_pick_best_crtc(scrn, FALSE, draw->x, draw->y, draw->width, draw->height); /* Update frontbuffer pixmap and name: Could have changed due to * window (un)redirection as part of compositing. */ front_updated = update_front(draw, s->dst); /* Assign frontbuffer pixmap, after update in update_front() */ dst_pix = nouveau_dri2_buffer(s->dst)->ppix; dst_bo = nouveau_pixmap_bo(dst_pix); /* Throttle on the previous frame before swapping */ nouveau_bo_wait(dst_bo, NOUVEAU_BO_RD, push->client); /* Swap by buffer exchange possible? */ will_exchange = front_updated && can_exchange(draw, dst_pix, src_pix); /* Only emit a wait for vblank pushbuf here if this is a copy-swap, or * if it is a kms pageflip-swap on an old kernel. Pure exchange swaps * don't need sync to vblank. kms pageflip-swaps on Linux 3.13+ are * synced to vblank in the kms driver, so we must not sync here, or * framerate will be cut in half! */ if (can_sync_to_vblank(draw) && (!will_exchange || (!pNv->has_async_pageflip && nouveau_exa_pixmap_is_onscreen(dst_pix)))) { /* Reference the back buffer to sync it to vblank */ nouveau_pushbuf_refn(push, &(struct nouveau_pushbuf_refn) { src_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD }, 1);
static RRCrtcPtr nouveau_present_crtc(WindowPtr window) { ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen); xf86CrtcPtr crtc; crtc = nouveau_pick_best_crtc(scrn, FALSE, window->drawable.x, window->drawable.y, window->drawable.width, window->drawable.height); if (!crtc) return NULL; if (crtc->rotatedData) return NULL; return crtc->randr_crtc; }
static int nouveau_wait_vblank(DrawablePtr draw, int type, CARD64 msc, CARD64 *pmsc, CARD64 *pust, void *data) { ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); NVPtr pNv = NVPTR(scrn); xf86CrtcPtr crtc; drmVBlank vbl; struct dri2_vblank *event = NULL; void *token = NULL; int ret; int head; /* Select crtc which shows the largest part of the drawable */ crtc = nouveau_pick_best_crtc(scrn, FALSE, draw->x, draw->y, draw->width, draw->height); if (!crtc) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Wait for VBlank failed: No valid crtc for drawable.\n"); return -EINVAL; } if (type & DRM_VBLANK_EVENT) { event = drmmode_event_queue(scrn, ++dri2_sequence, sizeof(*event), nouveau_dri2_vblank_handler, &token); if (!event) return -ENOMEM; event->s = data; } /* Map xf86CrtcPtr to drmWaitVBlank compatible display head index. */ head = drmmode_head(crtc); if (head == 1) type |= DRM_VBLANK_SECONDARY; else if (head > 1) #ifdef DRM_VBLANK_HIGH_CRTC_SHIFT type |= (head << DRM_VBLANK_HIGH_CRTC_SHIFT) & DRM_VBLANK_HIGH_CRTC_MASK; #else xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Wait for VBlank failed: Called for CRTC %d > 1, but " "DRM_VBLANK_HIGH_CRTC_SHIFT not defined at build time.\n", head); #endif vbl.request.type = type; vbl.request.sequence = msc; vbl.request.signal = (unsigned long)token; ret = drmWaitVBlank(pNv->dev->fd, &vbl); if (ret) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Wait for VBlank failed: %s\n", strerror(errno)); if (event) drmmode_event_abort(scrn, dri2_sequence--, false); return ret; } if (pmsc) *pmsc = vbl.reply.sequence; if (pust) *pust = (CARD64)vbl.reply.tval_sec * 1000000 + vbl.reply.tval_usec; return 0; }