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;
}
예제 #2
0
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);
}
예제 #4
0
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;
}