static Bool nouveau_present_flip_next(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t target_msc, PixmapPtr pixmap, Bool vsync) { xf86CrtcPtr crtc = rrcrtc->devPrivate; ScrnInfoPtr scrn = crtc->scrn; return nouveau_present_flip_exec(scrn, event_id, drmmode_crtc(crtc), target_msc, pixmap, vsync); }
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 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; }