static Bool nouveau_present_flip_exec(ScrnInfoPtr scrn, uint64_t event_id, int sync, uint64_t target_msc, PixmapPtr pixmap, Bool vsync) { ScreenPtr screen = scrn->pScreen; struct nouveau_pixmap *priv = NULL; NVPtr pNv = NVPTR(scrn); uint32_t next_fb; CARD16 stride; CARD32 size; void *token; int ret; #ifdef HAVE_GLAMOR if (pNv->AccelMethod == GLAMOR && !(priv = nouveau_glamor_pixmap_get(pixmap))) { int fd = glamor_fd_from_pixmap(screen, pixmap, &stride, &size); if (fd < 0) return FALSE; priv = calloc(1, sizeof(*priv)); if (!priv) return FALSE; ret = nouveau_bo_prime_handle_ref(pNv->dev, fd, &priv->bo); if (ret) { free(priv); return FALSE; } nouveau_glamor_pixmap_set(pixmap, priv); } else #endif if (!priv) priv = nouveau_pixmap(pixmap); ret = drmModeAddFB(pNv->dev->fd, pixmap->drawable.width, pixmap->drawable.height, pixmap->drawable.depth, pixmap->drawable.bitsPerPixel, pixmap->devKind, priv->bo->handle, &next_fb); if (ret == 0) { struct nouveau_present_flip *flip = drmmode_event_queue(scrn, event_id, sizeof(*flip), nouveau_present_flip, &token); if (flip) { xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); int last = 0, i; drmmode_swap(scrn, next_fb, &flip->old); flip->fd = pNv->dev->fd; flip->msc = target_msc; for (i = 0; i < config->num_crtc; i++) { if (config->crtc[i]->enabled) last = i; } for (i = 0; i < config->num_crtc; i++) { int type = vsync ? 0 : DRM_MODE_PAGE_FLIP_ASYNC; int crtc = drmmode_crtc(config->crtc[i]); void *user = NULL; if (!config->crtc[i]->enabled) continue; if (token && ((crtc == sync) || (i == last))) { type |= DRM_MODE_PAGE_FLIP_EVENT; user = token; } ret = drmModePageFlip(pNv->dev->fd, crtc, next_fb, type, user); if (ret == 0 && user) { token = NULL; } } if (token == NULL) { return TRUE; } drmmode_swap(scrn, flip->old, &next_fb); drmmode_event_abort(scrn, event_id, false); } drmModeRmFB(pNv->dev->fd, next_fb); } return FALSE; }
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; }
static void nouveau_present_vblank_abort(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc) { xf86CrtcPtr crtc = rrcrtc->devPrivate; drmmode_event_abort(crtc->scrn, event_id, true); }
static Bool dri2_page_flip(DrawablePtr draw, PixmapPtr back, void *priv, xf86CrtcPtr ref_crtc) { ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); NVPtr pNv = NVPTR(scrn); uint32_t next_fb; int emitted = 0; int ret, i; dri2_flipdata_ptr flipdata; dri2_flipevtcarrier_ptr flipcarrier; ret = drmModeAddFB(pNv->dev->fd, scrn->virtualX, scrn->virtualY, scrn->depth, scrn->bitsPerPixel, scrn->displayWidth * scrn->bitsPerPixel / 8, nouveau_pixmap(back)->bo->handle, &next_fb); if (ret) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "add fb failed: %s\n", strerror(errno)); return FALSE; } flipdata = calloc(1, sizeof(dri2_flipdata_rec)); if (!flipdata) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue: data alloc failed.\n"); goto error_undo; } flipdata->event_data = priv; flipdata->fd = pNv->dev->fd; for (i = 0; i < config->num_crtc; i++) { int head = drmmode_crtc(config->crtc[i]); void *token; if (!drmmode_crtc_on(config->crtc[i])) continue; flipdata->flip_count++; flipcarrier = drmmode_event_queue(scrn, ++dri2_sequence, sizeof(*flipcarrier), nouveau_dri2_flip_handler, &token); if (!flipcarrier) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue: carrier alloc failed.\n"); if (emitted == 0) free(flipdata); goto error_undo; } /* Only the reference crtc will finally deliver its page flip * completion event. All other crtc's events will be discarded. */ flipcarrier->dispatch_me = (config->crtc[i] == ref_crtc); flipcarrier->flipdata = flipdata; ret = drmModePageFlip(pNv->dev->fd, head, next_fb, DRM_MODE_PAGE_FLIP_EVENT, token); if (ret) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", strerror(errno)); drmmode_event_abort(scrn, dri2_sequence--, false); if (emitted == 0) free(flipdata); goto error_undo; } emitted++; } /* Will release old fb after all crtc's completed flip. */ drmmode_swap(scrn, next_fb, &flipdata->old_fb_id); return TRUE; error_undo: drmModeRmFB(pNv->dev->fd, next_fb); return FALSE; }