1fda9279dSmrg#include <sys/types.h>
2fda9279dSmrg#include <sys/stat.h>
3fda9279dSmrg#include <fcntl.h>
4fda9279dSmrg#include <errno.h>
5fda9279dSmrg
6fda9279dSmrg#include "xorg-server.h"
7fda9279dSmrg#include "nv_include.h"
8fda9279dSmrg#ifdef DRI2
9fda9279dSmrg#include "dri2.h"
10fda9279dSmrg#else
11fda9279dSmrg#error "This driver requires a DRI2-enabled X server"
12fda9279dSmrg#endif
1316ee1e9aSmrg#ifdef DRI3
1416ee1e9aSmrg#include "dri3.h"
1516ee1e9aSmrg#endif
16fda9279dSmrg#include "xf86drmMode.h"
17fda9279dSmrg
18fda9279dSmrgstruct nouveau_dri2_buffer {
19fda9279dSmrg	DRI2BufferRec base;
20fda9279dSmrg	PixmapPtr ppix;
21fda9279dSmrg};
22fda9279dSmrg
23fda9279dSmrgstatic inline struct nouveau_dri2_buffer *
24fda9279dSmrgnouveau_dri2_buffer(DRI2BufferPtr buf)
25fda9279dSmrg{
26fda9279dSmrg	return (struct nouveau_dri2_buffer *)buf;
27fda9279dSmrg}
28fda9279dSmrg
29fda9279dSmrgstatic PixmapPtr get_drawable_pixmap(DrawablePtr drawable)
30fda9279dSmrg{
31fda9279dSmrg	if (drawable->type == DRAWABLE_PIXMAP)
32fda9279dSmrg		return (PixmapPtr)drawable;
33fda9279dSmrg	else
34fda9279dSmrg		return (*drawable->pScreen->GetWindowPixmap)((WindowPtr)drawable);
35fda9279dSmrg}
36fda9279dSmrg
37dd52494dSmrgstatic DRI2BufferPtr
38fda9279dSmrgnouveau_dri2_create_buffer2(ScreenPtr pScreen, DrawablePtr pDraw, unsigned int attachment,
39fda9279dSmrg			   unsigned int format)
40fda9279dSmrg{
41fda9279dSmrg	NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen));
42fda9279dSmrg	struct nouveau_dri2_buffer *nvbuf;
43fda9279dSmrg	struct nouveau_pixmap *nvpix;
44fda9279dSmrg	PixmapPtr ppix = NULL;
45fda9279dSmrg
46fda9279dSmrg	nvbuf = calloc(1, sizeof(*nvbuf));
47fda9279dSmrg	if (!nvbuf)
48fda9279dSmrg		return NULL;
49fda9279dSmrg
50fda9279dSmrg	if (attachment == DRI2BufferFrontLeft) {
51fda9279dSmrg		ppix = get_drawable_pixmap(pDraw);
52fda9279dSmrg		if (pScreen != ppix->drawable.pScreen)
53fda9279dSmrg			ppix = NULL;
54fda9279dSmrg
55fda9279dSmrg		if (pDraw->type == DRAWABLE_WINDOW) {
56fda9279dSmrg#if DRI2INFOREC_VERSION >= 6
57fda9279dSmrg			/* Set initial swap limit on drawable. */
58fda9279dSmrg			DRI2SwapLimit(pDraw, pNv->swap_limit);
59fda9279dSmrg#endif
60fda9279dSmrg		}
61fda9279dSmrg		if (ppix)
62fda9279dSmrg			ppix->refcnt++;
63fda9279dSmrg	} else {
64fda9279dSmrg		int bpp;
6592405695Smrg		unsigned int usage_hint = 0;
6692405695Smrg
6792405695Smrg		if (pNv->Architecture >= NV_ARCH_10)
6892405695Smrg			usage_hint |= NOUVEAU_CREATE_PIXMAP_TILED;
69fda9279dSmrg
70fda9279dSmrg		/* 'format' is just depth (or 0, or maybe it depends on the caller) */
71fda9279dSmrg		bpp = round_up_pow2(format ? format : pDraw->depth);
72fda9279dSmrg
73fda9279dSmrg		if (attachment == DRI2BufferDepth ||
74fda9279dSmrg		    attachment == DRI2BufferDepthStencil)
75fda9279dSmrg			usage_hint |= NOUVEAU_CREATE_PIXMAP_ZETA;
76fda9279dSmrg		else
77fda9279dSmrg			usage_hint |= NOUVEAU_CREATE_PIXMAP_SCANOUT;
78fda9279dSmrg
79fda9279dSmrg		ppix = pScreen->CreatePixmap(pScreen, pDraw->width,
80fda9279dSmrg					     pDraw->height, bpp,
81fda9279dSmrg					     usage_hint);
82fda9279dSmrg	}
83fda9279dSmrg
84fda9279dSmrg	if (ppix) {
85fda9279dSmrg		pNv->exa_force_cp = TRUE;
86fda9279dSmrg		exaMoveInPixmap(ppix);
87fda9279dSmrg		pNv->exa_force_cp = FALSE;
88fda9279dSmrg
89fda9279dSmrg		nvbuf->base.pitch = ppix->devKind;
90fda9279dSmrg		nvbuf->base.cpp = ppix->drawable.bitsPerPixel / 8;
91fda9279dSmrg	}
92fda9279dSmrg
93fda9279dSmrg	nvbuf->base.attachment = attachment;
94fda9279dSmrg	nvbuf->base.driverPrivate = nvbuf;
95fda9279dSmrg	nvbuf->base.format = format;
96fda9279dSmrg	nvbuf->base.flags = 0;
97fda9279dSmrg	nvbuf->ppix = ppix;
98fda9279dSmrg
99fda9279dSmrg	if (ppix) {
100fda9279dSmrg		nvpix = nouveau_pixmap(ppix);
101fda9279dSmrg		if (!nvpix || !nvpix->bo ||
102fda9279dSmrg		    nouveau_bo_name_get(nvpix->bo, &nvbuf->base.name)) {
10333adc6acSmrg			dixDestroyPixmap(nvbuf->ppix, 0);
104fda9279dSmrg			free(nvbuf);
105fda9279dSmrg			return NULL;
106fda9279dSmrg		}
107fda9279dSmrg	}
108fda9279dSmrg	return &nvbuf->base;
109fda9279dSmrg}
110fda9279dSmrg
111dd52494dSmrgstatic DRI2BufferPtr
112fda9279dSmrgnouveau_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment,
113fda9279dSmrg			   unsigned int format)
114fda9279dSmrg{
115fda9279dSmrg	return nouveau_dri2_create_buffer2(pDraw->pScreen, pDraw,
116fda9279dSmrg					   attachment, format);
117fda9279dSmrg}
118fda9279dSmrg
119dd52494dSmrgstatic void
120fda9279dSmrgnouveau_dri2_destroy_buffer2(ScreenPtr pScreen, DrawablePtr pDraw, DRI2BufferPtr buf)
121fda9279dSmrg{
122fda9279dSmrg	struct nouveau_dri2_buffer *nvbuf;
123fda9279dSmrg
124fda9279dSmrg	nvbuf = nouveau_dri2_buffer(buf);
125fda9279dSmrg	if (!nvbuf)
126fda9279dSmrg		return;
127fda9279dSmrg
128fda9279dSmrg	if (nvbuf->ppix)
12933adc6acSmrg	    dixDestroyPixmap(nvbuf->ppix, 0);
130fda9279dSmrg	free(nvbuf);
131fda9279dSmrg}
132fda9279dSmrg
133dd52494dSmrgstatic void
134fda9279dSmrgnouveau_dri2_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buf)
135fda9279dSmrg{
136fda9279dSmrg	nouveau_dri2_destroy_buffer2(pDraw->pScreen, pDraw, buf);
137fda9279dSmrg}
138fda9279dSmrg
139dd52494dSmrgstatic void
140fda9279dSmrgnouveau_dri2_copy_region2(ScreenPtr pScreen, DrawablePtr pDraw, RegionPtr pRegion,
141fda9279dSmrg			 DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
142fda9279dSmrg{
143fda9279dSmrg	struct nouveau_dri2_buffer *src = nouveau_dri2_buffer(pSrcBuffer);
144fda9279dSmrg	struct nouveau_dri2_buffer *dst = nouveau_dri2_buffer(pDstBuffer);
145fda9279dSmrg	NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen));
146fda9279dSmrg	RegionPtr pCopyClip;
147fda9279dSmrg	GCPtr pGC;
148fda9279dSmrg	DrawablePtr src_draw, dst_draw;
149fda9279dSmrg	Bool translate = FALSE;
150fda9279dSmrg	int off_x = 0, off_y = 0;
151fda9279dSmrg
152fda9279dSmrg	src_draw = &src->ppix->drawable;
153fda9279dSmrg	dst_draw = &dst->ppix->drawable;
154fda9279dSmrg#if 0
155fda9279dSmrg	ErrorF("attachments src %d, dst %d, drawable %p %p pDraw %p\n",
156fda9279dSmrg	       src->base.attachment, dst->base.attachment,
157fda9279dSmrg	       src_draw, dst_draw, pDraw);
158fda9279dSmrg#endif
159fda9279dSmrg	if (src->base.attachment == DRI2BufferFrontLeft)
160fda9279dSmrg		src_draw = pDraw;
161fda9279dSmrg	if (dst->base.attachment == DRI2BufferFrontLeft) {
162fda9279dSmrg#ifdef NOUVEAU_PIXMAP_SHARING
163fda9279dSmrg		if (pDraw->pScreen != pScreen) {
164fda9279dSmrg			dst_draw = DRI2UpdatePrime(pDraw, pDstBuffer);
165fda9279dSmrg			if (!dst_draw)
166fda9279dSmrg				return;
167fda9279dSmrg		}
168fda9279dSmrg		else
169fda9279dSmrg#endif
170fda9279dSmrg			dst_draw = pDraw;
171fda9279dSmrg		if (dst_draw != pDraw)
172fda9279dSmrg			translate = TRUE;
173fda9279dSmrg	}
174fda9279dSmrg
175fda9279dSmrg	if (translate && pDraw->type == DRAWABLE_WINDOW) {
17616ee1e9aSmrg#ifdef COMPOSITE
177fda9279dSmrg		PixmapPtr pPix = get_drawable_pixmap(pDraw);
17816ee1e9aSmrg		off_x = -pPix->screen_x;
17916ee1e9aSmrg		off_y = -pPix->screen_y;
18016ee1e9aSmrg#endif
18116ee1e9aSmrg		off_x += pDraw->x;
18216ee1e9aSmrg		off_y += pDraw->y;
183fda9279dSmrg	}
184fda9279dSmrg
185fda9279dSmrg	pGC = GetScratchGC(pDraw->depth, pScreen);
186fda9279dSmrg	pCopyClip = REGION_CREATE(pScreen, NULL, 0);
187fda9279dSmrg	REGION_COPY(pScreen, pCopyClip, pRegion);
188fda9279dSmrg
189fda9279dSmrg	if (translate) {
190fda9279dSmrg		REGION_TRANSLATE(pScreen, pCopyClip, off_x, off_y);
191fda9279dSmrg	}
192fda9279dSmrg	pGC->funcs->ChangeClip(pGC, CT_REGION, pCopyClip, 0);
193fda9279dSmrg	ValidateGC(dst_draw, pGC);
194fda9279dSmrg
195fda9279dSmrg	/* If this is a full buffer swap or frontbuffer flush, throttle on
196fda9279dSmrg	 * the previous one.
197fda9279dSmrg	 */
198fda9279dSmrg	if (dst->base.attachment == DRI2BufferFrontLeft &&
199fda9279dSmrg	    REGION_NUM_RECTS(pRegion) == 1) {
200fda9279dSmrg		BoxPtr extents = REGION_EXTENTS(pScreen, pRegion);
201fda9279dSmrg		if (extents->x1 == 0 && extents->y1 == 0 &&
202fda9279dSmrg		    extents->x2 == pDraw->width &&
203fda9279dSmrg		    extents->y2 == pDraw->height) {
204fda9279dSmrg			PixmapPtr fpix = get_drawable_pixmap(dst_draw);
205fda9279dSmrg			struct nouveau_bo *bo = nouveau_pixmap_bo(fpix);
206fda9279dSmrg			if (bo)
207fda9279dSmrg				nouveau_bo_wait(bo, NOUVEAU_BO_RD, pNv->client);
208fda9279dSmrg		}
209fda9279dSmrg	}
210fda9279dSmrg
211fda9279dSmrg	pGC->ops->CopyArea(src_draw, dst_draw, pGC, 0, 0,
212fda9279dSmrg			   pDraw->width, pDraw->height, off_x, off_y);
213fda9279dSmrg
214fda9279dSmrg	FreeScratchGC(pGC);
215fda9279dSmrg}
216fda9279dSmrg
217dd52494dSmrgstatic void
218fda9279dSmrgnouveau_dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
219fda9279dSmrg			 DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
220fda9279dSmrg{
221fda9279dSmrg    return nouveau_dri2_copy_region2(pDraw->pScreen, pDraw, pRegion,
222fda9279dSmrg				     pDstBuffer, pSrcBuffer);
223fda9279dSmrg}
224fda9279dSmrg
225fda9279dSmrgstruct nouveau_dri2_vblank_state {
226fda9279dSmrg	enum {
227fda9279dSmrg		SWAP,
228fda9279dSmrg		BLIT,
229fda9279dSmrg		WAIT
230fda9279dSmrg	} action;
231fda9279dSmrg
232fda9279dSmrg	ClientPtr client;
233fda9279dSmrg	XID draw;
234fda9279dSmrg
235fda9279dSmrg	DRI2BufferPtr dst;
236fda9279dSmrg	DRI2BufferPtr src;
237fda9279dSmrg	DRI2SwapEventPtr func;
238fda9279dSmrg	void *data;
239fda9279dSmrg	unsigned int frame;
240fda9279dSmrg};
241fda9279dSmrg
242fda9279dSmrgstruct dri2_vblank {
243fda9279dSmrg	struct nouveau_dri2_vblank_state *s;
244fda9279dSmrg};
245fda9279dSmrg
246fda9279dSmrgstatic uint64_t dri2_sequence;
247fda9279dSmrg
248fda9279dSmrgstatic Bool
249fda9279dSmrgupdate_front(DrawablePtr draw, DRI2BufferPtr front)
250fda9279dSmrg{
25192405695Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
25292405695Smrg	NVPtr pNv = NVPTR(scrn);
253fda9279dSmrg	struct nouveau_dri2_buffer *nvbuf = nouveau_dri2_buffer(front);
25492405695Smrg	struct nouveau_bo *pixmap_bo;
25592405695Smrg
25692405695Smrg	PixmapPtr pixmap;
25792405695Smrg	int r;
258fda9279dSmrg
259fda9279dSmrg	if (draw->type == DRAWABLE_PIXMAP)
260fda9279dSmrg		pixmap = (PixmapPtr)draw;
261fda9279dSmrg	else
262fda9279dSmrg		pixmap = (*draw->pScreen->GetWindowPixmap)((WindowPtr)draw);
263fda9279dSmrg
264fda9279dSmrg	pixmap->refcnt++;
265fda9279dSmrg
26692405695Smrg	pNv->exa_force_cp = TRUE;
267fda9279dSmrg	exaMoveInPixmap(pixmap);
26892405695Smrg	pNv->exa_force_cp = FALSE;
26992405695Smrg	pixmap_bo = nouveau_pixmap_bo(pixmap);
27092405695Smrg
27192405695Smrg	if (!pixmap_bo)
27292405695Smrg		r = -1;
27392405695Smrg	else
27492405695Smrg		r = nouveau_bo_name_get(pixmap_bo, &front->name);
27592405695Smrg
276fda9279dSmrg	if (r) {
27733adc6acSmrg		dixDestroyPixmap(pixmap, 0);
278fda9279dSmrg		return FALSE;
279fda9279dSmrg	}
280fda9279dSmrg
281fda9279dSmrg	if (nvbuf->ppix)
28233adc6acSmrg		dixDestroyPixmap(nvbuf->ppix, 0);
283fda9279dSmrg
284fda9279dSmrg	front->pitch = pixmap->devKind;
285fda9279dSmrg	front->cpp = pixmap->drawable.bitsPerPixel / 8;
286fda9279dSmrg	nvbuf->ppix = pixmap;
287fda9279dSmrg
288fda9279dSmrg	return TRUE;
289fda9279dSmrg}
290fda9279dSmrg
291fda9279dSmrgstatic Bool
292fda9279dSmrgcan_exchange(DrawablePtr draw, PixmapPtr dst_pix, PixmapPtr src_pix)
293fda9279dSmrg{
294fda9279dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
295fda9279dSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
296fda9279dSmrg	NVPtr pNv = NVPTR(scrn);
297cd34e0e1Smrg	int i, active_crtc_count = 0;
298fda9279dSmrg
299fda9279dSmrg	if (!xf86_config->num_crtc)
300fda9279dSmrg		return FALSE;
301fda9279dSmrg
302fda9279dSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
303fda9279dSmrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
30433adc6acSmrg		if (xf86_crtc_on(crtc)) {
305cd34e0e1Smrg			if (crtc->rotatedData)
306cd34e0e1Smrg				return FALSE;
307fda9279dSmrg
308cd34e0e1Smrg			active_crtc_count++;
309cd34e0e1Smrg		}
310fda9279dSmrg	}
311fda9279dSmrg
312fda9279dSmrg	return ((DRI2CanFlip(draw) && pNv->has_pageflip)) &&
313fda9279dSmrg		dst_pix->drawable.width == src_pix->drawable.width &&
314fda9279dSmrg		dst_pix->drawable.height == src_pix->drawable.height &&
315fda9279dSmrg		dst_pix->drawable.bitsPerPixel == src_pix->drawable.bitsPerPixel &&
316cd34e0e1Smrg		dst_pix->devKind == src_pix->devKind &&
317cd34e0e1Smrg		active_crtc_count;
318fda9279dSmrg}
319fda9279dSmrg
320fda9279dSmrgstatic Bool
321fda9279dSmrgcan_sync_to_vblank(DrawablePtr draw)
322fda9279dSmrg{
323fda9279dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
324fda9279dSmrg	NVPtr pNv = NVPTR(scrn);
325fda9279dSmrg
326fda9279dSmrg	return pNv->glx_vblank &&
327fda9279dSmrg		nv_window_belongs_to_crtc(scrn, draw->x, draw->y,
328fda9279dSmrg					  draw->width, draw->height);
329fda9279dSmrg}
330fda9279dSmrg
331fda9279dSmrg#if DRI2INFOREC_VERSION >= 6
332fda9279dSmrgstatic Bool
333fda9279dSmrgnouveau_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit)
334fda9279dSmrg{
335fda9279dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
336fda9279dSmrg	NVPtr pNv = NVPTR(scrn);
337fda9279dSmrg
338fda9279dSmrg	if ((swap_limit < 1 ) || (swap_limit > pNv->max_swap_limit))
339fda9279dSmrg		return FALSE;
340fda9279dSmrg
341fda9279dSmrg	return TRUE;
342fda9279dSmrg}
343fda9279dSmrg#endif
344fda9279dSmrg
345fda9279dSmrg/* Shall we intentionally violate the OML_sync_control spec to
346fda9279dSmrg * get some sort of triple-buffering behaviour on a pre 1.12.0
347fda9279dSmrg * x-server?
348fda9279dSmrg */
349fda9279dSmrgstatic Bool violate_oml(DrawablePtr draw)
350fda9279dSmrg{
351fda9279dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
352fda9279dSmrg	NVPtr pNv = NVPTR(scrn);
353fda9279dSmrg
354fda9279dSmrg	return (DRI2INFOREC_VERSION < 6) && (pNv->swap_limit > 1);
355fda9279dSmrg}
356fda9279dSmrg
357fda9279dSmrgtypedef struct {
358fda9279dSmrg    int fd;
359fda9279dSmrg    unsigned old_fb_id;
360fda9279dSmrg    int flip_count;
361fda9279dSmrg    void *event_data;
362fda9279dSmrg    unsigned int fe_msc;
363fda9279dSmrg    uint64_t fe_ust;
364fda9279dSmrg} dri2_flipdata_rec, *dri2_flipdata_ptr;
365fda9279dSmrg
366fda9279dSmrgtypedef struct {
367fda9279dSmrg    dri2_flipdata_ptr flipdata;
368fda9279dSmrg    Bool dispatch_me;
369fda9279dSmrg} dri2_flipevtcarrier_rec, *dri2_flipevtcarrier_ptr;
370fda9279dSmrg
371fda9279dSmrgstatic void
372fda9279dSmrgnouveau_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
373fda9279dSmrg				unsigned int tv_usec, void *event_data)
374fda9279dSmrg{
375fda9279dSmrg	struct nouveau_dri2_vblank_state *flip = event_data;
376fda9279dSmrg	DrawablePtr draw;
377fda9279dSmrg	ScreenPtr screen;
378fda9279dSmrg	ScrnInfoPtr scrn;
379fda9279dSmrg	int status;
380fda9279dSmrg
381fda9279dSmrg	status = dixLookupDrawable(&draw, flip->draw, serverClient,
382fda9279dSmrg				   M_ANY, DixWriteAccess);
383fda9279dSmrg	if (status != Success) {
384fda9279dSmrg		free(flip);
385fda9279dSmrg		return;
386fda9279dSmrg	}
387fda9279dSmrg
388fda9279dSmrg	screen = draw->pScreen;
389fda9279dSmrg	scrn = xf86ScreenToScrn(screen);
390fda9279dSmrg
391fda9279dSmrg	/* We assume our flips arrive in order, so we don't check the frame */
392fda9279dSmrg	switch (flip->action) {
393fda9279dSmrg	case SWAP:
394fda9279dSmrg		/* Check for too small vblank count of pageflip completion,
395fda9279dSmrg		 * taking wraparound into account. This usually means some
396fda9279dSmrg		 * defective kms pageflip completion, causing wrong (msc, ust)
397fda9279dSmrg		 * return values and possible visual corruption.
398fda9279dSmrg		 * Skip test for frame == 0, as this is a valid constant value
399fda9279dSmrg		 * reported by all Linux kernels at least up to Linux 3.0.
400fda9279dSmrg		 */
401fda9279dSmrg		if ((frame != 0) &&
402fda9279dSmrg		    (frame < flip->frame) && (flip->frame - frame < 5)) {
403fda9279dSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
404fda9279dSmrg				   "%s: Pageflip has impossible msc %d < target_msc %d\n",
405fda9279dSmrg				   __func__, frame, flip->frame);
406fda9279dSmrg			/* All-Zero values signal failure of (msc, ust)
407fda9279dSmrg			 * timestamping to client.
408fda9279dSmrg			 */
409fda9279dSmrg			frame = tv_sec = tv_usec = 0;
410fda9279dSmrg		}
411fda9279dSmrg
412fda9279dSmrg		DRI2SwapComplete(flip->client, draw, frame, tv_sec, tv_usec,
413fda9279dSmrg				 DRI2_FLIP_COMPLETE, flip->func,
414fda9279dSmrg				 flip->data);
415fda9279dSmrg		break;
416fda9279dSmrg	default:
417fda9279dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
418fda9279dSmrg			   "%s: unknown vblank event received\n", __func__);
419fda9279dSmrg		/* Unknown type */
420fda9279dSmrg		break;
421fda9279dSmrg	}
422fda9279dSmrg
423fda9279dSmrg	free(flip);
424fda9279dSmrg}
425fda9279dSmrg
426fda9279dSmrgstatic void
427fda9279dSmrgnouveau_dri2_flip_handler(void *priv, uint64_t name, uint64_t ust, uint32_t msc)
428fda9279dSmrg{
429fda9279dSmrg	dri2_flipevtcarrier_ptr flipcarrier = priv;
430fda9279dSmrg	dri2_flipdata_ptr flipdata = flipcarrier->flipdata;
431fda9279dSmrg
432fda9279dSmrg	/* Is this the event whose info shall be delivered to higher level? */
433fda9279dSmrg	if (flipcarrier->dispatch_me) {
434fda9279dSmrg		/* Yes: Cache msc, ust for later delivery. */
435fda9279dSmrg		flipdata->fe_msc = msc;
436fda9279dSmrg		flipdata->fe_ust = ust;
437fda9279dSmrg	}
438fda9279dSmrg
439fda9279dSmrg	/* Last crtc completed flip? */
440fda9279dSmrg	flipdata->flip_count--;
441fda9279dSmrg	if (flipdata->flip_count > 0)
442fda9279dSmrg		return;
443fda9279dSmrg
444fda9279dSmrg	/* Release framebuffer */
445fda9279dSmrg	drmModeRmFB(flipdata->fd, flipdata->old_fb_id);
446fda9279dSmrg
447fda9279dSmrg	if (flipdata->event_data == NULL) {
448fda9279dSmrg		free(flipdata);
449fda9279dSmrg		return;
450fda9279dSmrg	}
451fda9279dSmrg
452fda9279dSmrg	/* Deliver cached msc, ust from reference crtc to flip event handler */
453fda9279dSmrg	nouveau_dri2_flip_event_handler(flipdata->fe_msc,
454fda9279dSmrg					flipdata->fe_ust / 1000000,
455fda9279dSmrg					flipdata->fe_ust % 1000000,
456fda9279dSmrg					flipdata->event_data);
457fda9279dSmrg	free(flipdata);
458fda9279dSmrg}
459fda9279dSmrg
460fda9279dSmrgstatic Bool
461fda9279dSmrgdri2_page_flip(DrawablePtr draw, PixmapPtr back, void *priv,
462fda9279dSmrg			   xf86CrtcPtr ref_crtc)
463fda9279dSmrg{
464fda9279dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
465fda9279dSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
466fda9279dSmrg	NVPtr pNv = NVPTR(scrn);
467fda9279dSmrg	uint32_t next_fb;
468fda9279dSmrg	int emitted = 0;
469fda9279dSmrg	int ret, i;
470fda9279dSmrg	dri2_flipdata_ptr flipdata;
471fda9279dSmrg	dri2_flipevtcarrier_ptr flipcarrier;
472fda9279dSmrg
473fda9279dSmrg	ret = drmModeAddFB(pNv->dev->fd, scrn->virtualX, scrn->virtualY,
474fda9279dSmrg			   scrn->depth, scrn->bitsPerPixel,
475fda9279dSmrg			   scrn->displayWidth * scrn->bitsPerPixel / 8,
476fda9279dSmrg			   nouveau_pixmap(back)->bo->handle, &next_fb);
477fda9279dSmrg	if (ret) {
478fda9279dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
479fda9279dSmrg			   "add fb failed: %s\n", strerror(errno));
480fda9279dSmrg		return FALSE;
481fda9279dSmrg	}
482fda9279dSmrg
483fda9279dSmrg	flipdata = calloc(1, sizeof(dri2_flipdata_rec));
484fda9279dSmrg	if (!flipdata) {
485fda9279dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
486fda9279dSmrg		"flip queue: data alloc failed.\n");
487fda9279dSmrg		goto error_undo;
488fda9279dSmrg	}
489fda9279dSmrg
490fda9279dSmrg	flipdata->event_data = priv;
491fda9279dSmrg	flipdata->fd = pNv->dev->fd;
492fda9279dSmrg
493fda9279dSmrg	for (i = 0; i < config->num_crtc; i++) {
494fda9279dSmrg		int head = drmmode_crtc(config->crtc[i]);
495fda9279dSmrg		void *token;
496fda9279dSmrg
49733adc6acSmrg		if (!xf86_crtc_on(config->crtc[i]))
498fda9279dSmrg			continue;
499fda9279dSmrg
500fda9279dSmrg		flipdata->flip_count++;
501fda9279dSmrg
502fda9279dSmrg		flipcarrier = drmmode_event_queue(scrn, ++dri2_sequence,
503fda9279dSmrg						  sizeof(*flipcarrier),
504fda9279dSmrg						  nouveau_dri2_flip_handler,
505fda9279dSmrg						  &token);
506fda9279dSmrg		if (!flipcarrier) {
507fda9279dSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
508fda9279dSmrg				   "flip queue: carrier alloc failed.\n");
509fda9279dSmrg			if (emitted == 0)
510fda9279dSmrg				free(flipdata);
511fda9279dSmrg			goto error_undo;
512fda9279dSmrg		}
513fda9279dSmrg
514fda9279dSmrg		/* Only the reference crtc will finally deliver its page flip
515fda9279dSmrg		 * completion event. All other crtc's events will be discarded.
516fda9279dSmrg		 */
517fda9279dSmrg		flipcarrier->dispatch_me = (config->crtc[i] == ref_crtc);
518fda9279dSmrg		flipcarrier->flipdata = flipdata;
519fda9279dSmrg
520fda9279dSmrg		ret = drmModePageFlip(pNv->dev->fd, head, next_fb,
521fda9279dSmrg				      DRM_MODE_PAGE_FLIP_EVENT, token);
522fda9279dSmrg		if (ret) {
523fda9279dSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
524fda9279dSmrg				   "flip queue failed: %s\n", strerror(errno));
525fda9279dSmrg			drmmode_event_abort(scrn, dri2_sequence--, false);
526fda9279dSmrg			if (emitted == 0)
527fda9279dSmrg				free(flipdata);
528fda9279dSmrg			goto error_undo;
529fda9279dSmrg		}
530fda9279dSmrg
531fda9279dSmrg		emitted++;
532fda9279dSmrg	}
533fda9279dSmrg
534fda9279dSmrg	/* Will release old fb after all crtc's completed flip. */
535fda9279dSmrg	drmmode_swap(scrn, next_fb, &flipdata->old_fb_id);
536fda9279dSmrg	return TRUE;
537fda9279dSmrg
538fda9279dSmrgerror_undo:
539fda9279dSmrg	drmModeRmFB(pNv->dev->fd, next_fb);
540fda9279dSmrg	return FALSE;
541fda9279dSmrg}
542fda9279dSmrg
543fda9279dSmrgstatic void
544fda9279dSmrgnouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
545fda9279dSmrg			 unsigned int tv_sec, unsigned int tv_usec,
546fda9279dSmrg			 struct nouveau_dri2_vblank_state *s);
547fda9279dSmrg
548fda9279dSmrgstatic void
549fda9279dSmrgnouveau_dri2_vblank_handler(void *priv, uint64_t name, uint64_t ust, uint32_t frame)
550fda9279dSmrg{
551fda9279dSmrg	struct dri2_vblank *event = priv;
552fda9279dSmrg	struct nouveau_dri2_vblank_state *s = event->s;
553fda9279dSmrg	uint32_t tv_sec  = ust / 1000000;
554fda9279dSmrg	uint32_t tv_usec = ust % 1000000;
555fda9279dSmrg	DrawablePtr draw;
556fda9279dSmrg	int ret;
557fda9279dSmrg
558fda9279dSmrg	ret = dixLookupDrawable(&draw, s->draw, serverClient,
559fda9279dSmrg				M_ANY, DixWriteAccess);
560fda9279dSmrg	if (ret) {
561fda9279dSmrg		free(s);
562fda9279dSmrg		return;
563fda9279dSmrg	}
564fda9279dSmrg
565fda9279dSmrg	switch (s->action) {
566fda9279dSmrg	case SWAP:
567fda9279dSmrg		nouveau_dri2_finish_swap(draw, frame, tv_sec, tv_usec, s);
568fda9279dSmrg#if DRI2INFOREC_VERSION >= 6
569fda9279dSmrg		/* Restore real swap limit on drawable, now that it is safe. */
570fda9279dSmrg		ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
571fda9279dSmrg		DRI2SwapLimit(draw, NVPTR(scrn)->swap_limit);
572fda9279dSmrg#endif
573fda9279dSmrg		break;
574fda9279dSmrg
575fda9279dSmrg	case WAIT:
576fda9279dSmrg		DRI2WaitMSCComplete(s->client, draw, frame, tv_sec, tv_usec);
577fda9279dSmrg		free(s);
578fda9279dSmrg		break;
579fda9279dSmrg
580fda9279dSmrg	case BLIT:
581fda9279dSmrg		DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec,
582fda9279dSmrg				 DRI2_BLIT_COMPLETE, s->func, s->data);
583fda9279dSmrg		free(s);
584fda9279dSmrg		break;
585fda9279dSmrg	}
586fda9279dSmrg}
587fda9279dSmrg
588fda9279dSmrgstatic int
589fda9279dSmrgnouveau_wait_vblank(DrawablePtr draw, int type, CARD64 msc,
590fda9279dSmrg		    CARD64 *pmsc, CARD64 *pust, void *data)
591fda9279dSmrg{
592fda9279dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
593fda9279dSmrg	NVPtr pNv = NVPTR(scrn);
594fda9279dSmrg	xf86CrtcPtr crtc;
595fda9279dSmrg	drmVBlank vbl;
596fda9279dSmrg	struct dri2_vblank *event = NULL;
597fda9279dSmrg	void *token = NULL;
598fda9279dSmrg	int ret;
599fda9279dSmrg	int head;
600fda9279dSmrg
601fda9279dSmrg	/* Select crtc which shows the largest part of the drawable */
60233adc6acSmrg	crtc = nouveau_pick_best_crtc(scrn,
60333adc6acSmrg				      draw->x, draw->y, draw->width, draw->height);
604fda9279dSmrg
605fda9279dSmrg	if (!crtc) {
606fda9279dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
607fda9279dSmrg				   "Wait for VBlank failed: No valid crtc for drawable.\n");
608fda9279dSmrg		return -EINVAL;
609fda9279dSmrg	}
610fda9279dSmrg
611fda9279dSmrg	if (type & DRM_VBLANK_EVENT) {
612fda9279dSmrg		event = drmmode_event_queue(scrn, ++dri2_sequence,
613fda9279dSmrg					    sizeof(*event),
614fda9279dSmrg					    nouveau_dri2_vblank_handler,
615fda9279dSmrg					    &token);
616fda9279dSmrg		if (!event)
617fda9279dSmrg			return -ENOMEM;
618fda9279dSmrg
619fda9279dSmrg		event->s = data;
620fda9279dSmrg	}
621fda9279dSmrg
622fda9279dSmrg	/* Map xf86CrtcPtr to drmWaitVBlank compatible display head index. */
623fda9279dSmrg	head = drmmode_head(crtc);
624fda9279dSmrg
625fda9279dSmrg	if (head == 1)
626fda9279dSmrg		type |= DRM_VBLANK_SECONDARY;
627fda9279dSmrg	else if (head > 1)
628fda9279dSmrg#ifdef DRM_VBLANK_HIGH_CRTC_SHIFT
629fda9279dSmrg		type |= (head << DRM_VBLANK_HIGH_CRTC_SHIFT) &
630fda9279dSmrg				DRM_VBLANK_HIGH_CRTC_MASK;
631fda9279dSmrg#else
632fda9279dSmrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
633fda9279dSmrg			   "Wait for VBlank failed: Called for CRTC %d > 1, but "
634fda9279dSmrg			   "DRM_VBLANK_HIGH_CRTC_SHIFT not defined at build time.\n",
635fda9279dSmrg			   head);
636fda9279dSmrg#endif
637fda9279dSmrg
638fda9279dSmrg	vbl.request.type = type;
639fda9279dSmrg	vbl.request.sequence = msc;
640fda9279dSmrg	vbl.request.signal = (unsigned long)token;
641fda9279dSmrg
642fda9279dSmrg	ret = drmWaitVBlank(pNv->dev->fd, &vbl);
643fda9279dSmrg	if (ret) {
644fda9279dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
645fda9279dSmrg			   "Wait for VBlank failed: %s\n", strerror(errno));
646fda9279dSmrg		if (event)
647fda9279dSmrg			drmmode_event_abort(scrn, dri2_sequence--, false);
648fda9279dSmrg		return ret;
649fda9279dSmrg	}
650fda9279dSmrg
651fda9279dSmrg	if (pmsc)
652fda9279dSmrg		*pmsc = vbl.reply.sequence;
653fda9279dSmrg	if (pust)
654fda9279dSmrg		*pust = (CARD64)vbl.reply.tval_sec * 1000000 +
655fda9279dSmrg			vbl.reply.tval_usec;
656fda9279dSmrg	return 0;
657fda9279dSmrg}
658fda9279dSmrg
659fda9279dSmrgstatic void
660fda9279dSmrgnouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
661fda9279dSmrg			 unsigned int tv_sec, unsigned int tv_usec,
662fda9279dSmrg			 struct nouveau_dri2_vblank_state *s)
663fda9279dSmrg{
664fda9279dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
665fda9279dSmrg	NVPtr pNv = NVPTR(scrn);
666fda9279dSmrg	PixmapPtr dst_pix;
667fda9279dSmrg	PixmapPtr src_pix = nouveau_dri2_buffer(s->src)->ppix;
668fda9279dSmrg	struct nouveau_bo *dst_bo;
669fda9279dSmrg	struct nouveau_bo *src_bo = nouveau_pixmap_bo(src_pix);
670fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
671fda9279dSmrg	RegionRec reg;
672fda9279dSmrg	int type, ret;
673fda9279dSmrg	Bool front_updated, will_exchange;
674fda9279dSmrg	xf86CrtcPtr ref_crtc;
675fda9279dSmrg
676fda9279dSmrg	REGION_INIT(0, &reg, (&(BoxRec){ 0, 0, draw->width, draw->height }), 0);
677fda9279dSmrg	REGION_TRANSLATE(0, &reg, draw->x, draw->y);
678fda9279dSmrg
679fda9279dSmrg	/* Main crtc for this drawable shall finally deliver pageflip event. */
68033adc6acSmrg	ref_crtc = nouveau_pick_best_crtc(scrn, draw->x, draw->y,
68133adc6acSmrg					  draw->width, draw->height);
682fda9279dSmrg
683fda9279dSmrg	/* Update frontbuffer pixmap and name: Could have changed due to
684fda9279dSmrg	 * window (un)redirection as part of compositing.
685fda9279dSmrg	 */
686fda9279dSmrg	front_updated = update_front(draw, s->dst);
687fda9279dSmrg
688fda9279dSmrg	/* Assign frontbuffer pixmap, after update in update_front() */
689fda9279dSmrg	dst_pix = nouveau_dri2_buffer(s->dst)->ppix;
690fda9279dSmrg	dst_bo = nouveau_pixmap_bo(dst_pix);
691fda9279dSmrg
692fda9279dSmrg	/* Throttle on the previous frame before swapping */
693fda9279dSmrg	nouveau_bo_wait(dst_bo, NOUVEAU_BO_RD, push->client);
694fda9279dSmrg
695fda9279dSmrg	/* Swap by buffer exchange possible? */
696fda9279dSmrg	will_exchange = front_updated && can_exchange(draw, dst_pix, src_pix);
697fda9279dSmrg
698fda9279dSmrg	/* Only emit a wait for vblank pushbuf here if this is a copy-swap, or
699fda9279dSmrg	 * if it is a kms pageflip-swap on an old kernel. Pure exchange swaps
700fda9279dSmrg	 * don't need sync to vblank. kms pageflip-swaps on Linux 3.13+ are
701fda9279dSmrg	 * synced to vblank in the kms driver, so we must not sync here, or
702fda9279dSmrg	 * framerate will be cut in half!
703fda9279dSmrg	 */
704fda9279dSmrg	if (can_sync_to_vblank(draw) &&
705fda9279dSmrg		(!will_exchange ||
706fda9279dSmrg		(!pNv->has_async_pageflip && nouveau_exa_pixmap_is_onscreen(dst_pix)))) {
707fda9279dSmrg		/* Reference the back buffer to sync it to vblank */
708fda9279dSmrg		nouveau_pushbuf_refn(push, &(struct nouveau_pushbuf_refn) {
709fda9279dSmrg					   src_bo,
710fda9279dSmrg					   NOUVEAU_BO_VRAM | NOUVEAU_BO_RD
711fda9279dSmrg				     }, 1);
712fda9279dSmrg
713fda9279dSmrg		if (pNv->Architecture >= NV_FERMI)
714fda9279dSmrg			NVC0SyncToVBlank(dst_pix, REGION_EXTENTS(0, &reg));
715fda9279dSmrg		else
716fda9279dSmrg		if (pNv->Architecture >= NV_TESLA)
717fda9279dSmrg			NV50SyncToVBlank(dst_pix, REGION_EXTENTS(0, &reg));
718fda9279dSmrg		else
719fda9279dSmrg			NV11SyncToVBlank(dst_pix, REGION_EXTENTS(0, &reg));
720fda9279dSmrg
721fda9279dSmrg		nouveau_pushbuf_kick(push, push->channel);
722fda9279dSmrg	}
723fda9279dSmrg
724fda9279dSmrg	if (will_exchange) {
725fda9279dSmrg		type = DRI2_EXCHANGE_COMPLETE;
726fda9279dSmrg		DamageRegionAppend(draw, &reg);
727fda9279dSmrg
728fda9279dSmrg		if (nouveau_exa_pixmap_is_onscreen(dst_pix)) {
729fda9279dSmrg			type = DRI2_FLIP_COMPLETE;
730fda9279dSmrg			ret = dri2_page_flip(draw, src_pix, violate_oml(draw) ?
731fda9279dSmrg					     NULL : s, ref_crtc);
732fda9279dSmrg			if (!ret)
733fda9279dSmrg				goto out;
734fda9279dSmrg		}
735fda9279dSmrg
736fda9279dSmrg		SWAP(s->dst->name, s->src->name);
737fda9279dSmrg		SWAP(nouveau_pixmap(dst_pix)->bo, nouveau_pixmap(src_pix)->bo);
738fda9279dSmrg
739fda9279dSmrg		DamageRegionProcessPending(draw);
740fda9279dSmrg
741fda9279dSmrg		/* If it is a page flip, finish it in the flip event handler. */
742fda9279dSmrg		if ((type == DRI2_FLIP_COMPLETE) && !violate_oml(draw))
743fda9279dSmrg			return;
744fda9279dSmrg	} else {
745fda9279dSmrg		type = DRI2_BLIT_COMPLETE;
746fda9279dSmrg
747fda9279dSmrg		/* Reference the front buffer to let throttling work
748fda9279dSmrg		 * on occluded drawables. */
749fda9279dSmrg		nouveau_pushbuf_refn(push, &(struct nouveau_pushbuf_refn) {
750fda9279dSmrg					   dst_bo,
751fda9279dSmrg					   NOUVEAU_BO_VRAM | NOUVEAU_BO_RD
752fda9279dSmrg				     }, 1);
753fda9279dSmrg
754fda9279dSmrg		REGION_TRANSLATE(0, &reg, -draw->x, -draw->y);
755fda9279dSmrg		nouveau_dri2_copy_region(draw, &reg, s->dst, s->src);
756fda9279dSmrg
757fda9279dSmrg		if (can_sync_to_vblank(draw) && !violate_oml(draw)) {
758fda9279dSmrg			/* Request a vblank event one vblank from now, the most
759fda9279dSmrg			 * likely (optimistic?) time a direct framebuffer blit
760fda9279dSmrg			 * will complete or a desktop compositor will update its
761fda9279dSmrg			 * screen. This defers DRI2SwapComplete() to the earliest
762fda9279dSmrg			 * likely time of real swap completion.
763fda9279dSmrg			 */
764fda9279dSmrg			s->action = BLIT;
765fda9279dSmrg			ret = nouveau_wait_vblank(draw, DRM_VBLANK_EVENT |
766fda9279dSmrg						  DRM_VBLANK_RELATIVE, 1,
767fda9279dSmrg						  NULL, NULL, s);
768fda9279dSmrg			/* Done, if success. Otherwise use fallback below. */
769fda9279dSmrg			if (!ret)
770fda9279dSmrg				return;
771fda9279dSmrg		}
772fda9279dSmrg	}
773fda9279dSmrg
774fda9279dSmrg	/* Special triple-buffering hack for old pre 1.12.0 x-servers used? */
775fda9279dSmrg	if (violate_oml(draw)) {
776fda9279dSmrg		/* Signal to client that swap completion timestamps and counts
777fda9279dSmrg		 * are invalid - they violate the specification.
778fda9279dSmrg		 */
779fda9279dSmrg		frame = tv_sec = tv_usec = 0;
780fda9279dSmrg	}
781fda9279dSmrg
782fda9279dSmrg	/*
783fda9279dSmrg	 * Tell the X server buffers are already swapped even if they're
784fda9279dSmrg	 * not, to prevent it from blocking the client on the next
785fda9279dSmrg	 * GetBuffers request (and let the client do triple-buffering).
786fda9279dSmrg	 *
787fda9279dSmrg	 * XXX - The DRI2SwapLimit() API allowed us to move this to
788fda9279dSmrg	 *	 the flip handler with no FPS hit for page flipped swaps.
789fda9279dSmrg	 *       It is still needed as a fallback for some copy swaps as
790fda9279dSmrg	 *       we lack a method to detect true swap completion for
791fda9279dSmrg	 *       DRI2_BLIT_COMPLETE.
792fda9279dSmrg	 *
793fda9279dSmrg	 *       It is also used if triple-buffering is requested on
794fda9279dSmrg	 *       old x-servers which don't support the DRI2SwapLimit()
795fda9279dSmrg	 *       function.
796fda9279dSmrg	 */
797fda9279dSmrg	DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec,
798fda9279dSmrg			 type, s->func, s->data);
799fda9279dSmrgout:
800fda9279dSmrg	free(s);
801fda9279dSmrg}
802fda9279dSmrg
803fda9279dSmrgstatic Bool
804fda9279dSmrgnouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
805fda9279dSmrg			   DRI2BufferPtr dst, DRI2BufferPtr src,
806fda9279dSmrg			   CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
807fda9279dSmrg			   DRI2SwapEventPtr func, void *data)
808fda9279dSmrg{
809fda9279dSmrg	struct nouveau_dri2_vblank_state *s;
810fda9279dSmrg	CARD64 current_msc, expect_msc;
811fda9279dSmrg	CARD64 current_ust;
812fda9279dSmrg	int ret;
813fda9279dSmrg
814fda9279dSmrg	/* Initialize a swap structure */
815fda9279dSmrg	s = malloc(sizeof(*s));
816fda9279dSmrg	if (!s)
817fda9279dSmrg		return FALSE;
818fda9279dSmrg
819fda9279dSmrg	*s = (struct nouveau_dri2_vblank_state)
820fda9279dSmrg		{ SWAP, client, draw->id, dst, src, func, data, 0 };
821fda9279dSmrg
822fda9279dSmrg	if (can_sync_to_vblank(draw)) {
823fda9279dSmrg		/* Get current sequence and vblank time*/
824fda9279dSmrg		ret = nouveau_wait_vblank(draw, DRM_VBLANK_RELATIVE, 0,
825fda9279dSmrg					  &current_msc, &current_ust, NULL);
826fda9279dSmrg		if (ret)
827fda9279dSmrg			goto fail;
828fda9279dSmrg
829fda9279dSmrg		/* Truncate to match kernel interfaces; means occasional overflow
830fda9279dSmrg		 * misses, but that's generally not a big deal.
831fda9279dSmrg		 */
832fda9279dSmrg		*target_msc &= 0xffffffff;
833fda9279dSmrg		divisor &= 0xffffffff;
834fda9279dSmrg		remainder &= 0xffffffff;
835fda9279dSmrg
836fda9279dSmrg		/* Calculate a swap target if we don't have one */
837fda9279dSmrg		if (current_msc >= *target_msc && divisor)
838fda9279dSmrg			*target_msc = current_msc + divisor
839fda9279dSmrg				- (current_msc - remainder) % divisor;
840fda9279dSmrg
841fda9279dSmrg		/* Avoid underflow of unsigned value below */
842fda9279dSmrg		if (*target_msc == 0)
843fda9279dSmrg			*target_msc = 1;
844fda9279dSmrg
845fda9279dSmrg		/* Swap at next possible vblank requested? */
846fda9279dSmrg		if (current_msc >= *target_msc - 1) {
847fda9279dSmrg			/* Special case: Need to swap at next vblank.
848fda9279dSmrg			 * Schedule swap immediately, bypassing the kernel
849fda9279dSmrg			 * vblank event mechanism to avoid a dangerous race
850fda9279dSmrg			 * between the client and the x-server vblank event
851fda9279dSmrg			 * dispatch in the main x-server dispatch loop when
852fda9279dSmrg			 * the swap_limit is set to 2 for triple-buffering.
853fda9279dSmrg			 *
854fda9279dSmrg			 * This also optimizes for the common case of swap
855fda9279dSmrg			 * at next vblank, avoiding vblank dispatch delay.
856fda9279dSmrg			 */
857fda9279dSmrg			s->frame = 1 + ((unsigned int) current_msc & 0xffffffff);
858fda9279dSmrg			*target_msc = 1 + current_msc;
859fda9279dSmrg			nouveau_dri2_finish_swap(draw, current_msc,
860fda9279dSmrg						 (unsigned int) (current_ust / 1000000),
861fda9279dSmrg						 (unsigned int) (current_ust % 1000000),
862fda9279dSmrg						 s);
863fda9279dSmrg			return TRUE;
864fda9279dSmrg		}
865fda9279dSmrg
866fda9279dSmrg		/* This is a swap in the future, ie. the vblank event will
867fda9279dSmrg		 * only get dispatched at least 2 vblanks into the future.
868fda9279dSmrg		 */
869fda9279dSmrg
870fda9279dSmrg#if DRI2INFOREC_VERSION >= 6
871fda9279dSmrg		/* On XOrg 1.12+ we need to temporarily lower the swaplimit to 1,
872fda9279dSmrg		 * so that DRI2GetBuffersWithFormat() requests from the client get
873fda9279dSmrg		 * deferred in the x-server until the vblank event has been
874fda9279dSmrg		 * dispatched to us and nouveau_dri2_finish_swap() is done. If
875fda9279dSmrg		 * we wouldn't do this, DRI2GetBuffersWithFormat() would operate
876fda9279dSmrg		 * on wrong (pre-swap) buffers, and cause a segfault later on in
877fda9279dSmrg		 * nouveau_dri2_finish_swap(). Our vblank event handler will restore
878fda9279dSmrg		 * the old swaplimit immediately after nouveau_dri2_finish_swap()
879fda9279dSmrg		 * is done, so we still get 1 video refresh cycle worth of triple-
880fda9279dSmrg		 * buffering, because the client can start rendering again 1 cycle
881fda9279dSmrg		 * before the pending swap is completed.
882fda9279dSmrg		 *
883fda9279dSmrg		 * The same race would happen for the "swap at next vblank" case,
884fda9279dSmrg		 * but the special case "swap immediately" code above prevents this.
885fda9279dSmrg		 */
886fda9279dSmrg		DRI2SwapLimit(draw, 1);
887fda9279dSmrg#endif
888fda9279dSmrg
889fda9279dSmrg		/* Request a vblank event one frame before the target */
890fda9279dSmrg		ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE |
891fda9279dSmrg					  DRM_VBLANK_EVENT,
892fda9279dSmrg					  max(current_msc, *target_msc - 1),
893fda9279dSmrg					  &expect_msc, NULL, s);
894fda9279dSmrg		if (ret)
895fda9279dSmrg			goto fail;
896fda9279dSmrg		s->frame = 1 + ((unsigned int) expect_msc & 0xffffffff);
897fda9279dSmrg		*target_msc = 1 + expect_msc;
898fda9279dSmrg	} else {
899fda9279dSmrg		/* We can't/don't want to sync to vblank, just swap. */
900fda9279dSmrg		nouveau_dri2_finish_swap(draw, 0, 0, 0, s);
901fda9279dSmrg	}
902fda9279dSmrg
903fda9279dSmrg	return TRUE;
904fda9279dSmrg
905fda9279dSmrgfail:
906fda9279dSmrg	free(s);
907fda9279dSmrg	return FALSE;
908fda9279dSmrg}
909fda9279dSmrg
910fda9279dSmrgstatic Bool
911fda9279dSmrgnouveau_dri2_schedule_wait(ClientPtr client, DrawablePtr draw,
912fda9279dSmrg			   CARD64 target_msc, CARD64 divisor, CARD64 remainder)
913fda9279dSmrg{
914fda9279dSmrg	struct nouveau_dri2_vblank_state *s;
915fda9279dSmrg	CARD64 current_msc;
916fda9279dSmrg	int ret;
917fda9279dSmrg
918fda9279dSmrg	/* Truncate to match kernel interfaces; means occasional overflow
919fda9279dSmrg	 * misses, but that's generally not a big deal.
920fda9279dSmrg	 */
921fda9279dSmrg	target_msc &= 0xffffffff;
922fda9279dSmrg	divisor &= 0xffffffff;
923fda9279dSmrg	remainder &= 0xffffffff;
924fda9279dSmrg
925fda9279dSmrg	if (!can_sync_to_vblank(draw)) {
926fda9279dSmrg		DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
927fda9279dSmrg		return TRUE;
928fda9279dSmrg	}
929fda9279dSmrg
930fda9279dSmrg	/* Initialize a vblank structure */
931fda9279dSmrg	s = malloc(sizeof(*s));
932fda9279dSmrg	if (!s)
933fda9279dSmrg		return FALSE;
934fda9279dSmrg
935fda9279dSmrg	*s = (struct nouveau_dri2_vblank_state) { WAIT, client, draw->id };
936fda9279dSmrg
937fda9279dSmrg	/* Get current sequence */
938fda9279dSmrg	ret = nouveau_wait_vblank(draw, DRM_VBLANK_RELATIVE, 0,
939fda9279dSmrg				  &current_msc, NULL, NULL);
940fda9279dSmrg	if (ret)
941fda9279dSmrg		goto fail;
942fda9279dSmrg
943fda9279dSmrg	/* Calculate a wait target if we don't have one */
944fda9279dSmrg	if (current_msc >= target_msc && divisor)
945fda9279dSmrg		target_msc = current_msc + divisor
946fda9279dSmrg			- (current_msc - remainder) % divisor;
947fda9279dSmrg
948fda9279dSmrg	/* Request a vblank event */
949fda9279dSmrg	ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE |
950fda9279dSmrg				  DRM_VBLANK_EVENT,
951fda9279dSmrg				  max(current_msc, target_msc),
952fda9279dSmrg				  NULL, NULL, s);
953fda9279dSmrg	if (ret)
954fda9279dSmrg		goto fail;
955fda9279dSmrg
956fda9279dSmrg	DRI2BlockClient(client, draw);
957fda9279dSmrg	return TRUE;
958fda9279dSmrgfail:
959fda9279dSmrg	free(s);
960fda9279dSmrg	return FALSE;
961fda9279dSmrg}
962fda9279dSmrg
963fda9279dSmrgstatic Bool
964fda9279dSmrgnouveau_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
965fda9279dSmrg{
966fda9279dSmrg	int ret;
967fda9279dSmrg
968fda9279dSmrg	if (!can_sync_to_vblank(draw)) {
969fda9279dSmrg		*ust = 0;
970fda9279dSmrg		*msc = 0;
971fda9279dSmrg		return TRUE;
972fda9279dSmrg	}
973fda9279dSmrg
974fda9279dSmrg	/* Get current sequence */
975fda9279dSmrg	ret = nouveau_wait_vblank(draw, DRM_VBLANK_RELATIVE, 0, msc, ust, NULL);
976fda9279dSmrg	if (ret)
977fda9279dSmrg		return FALSE;
978fda9279dSmrg
979fda9279dSmrg	return TRUE;
980fda9279dSmrg}
981fda9279dSmrg
982fda9279dSmrgBool
983fda9279dSmrgnouveau_dri2_init(ScreenPtr pScreen)
984fda9279dSmrg{
985fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
986fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
987fda9279dSmrg	DRI2InfoRec dri2 = { 0 };
988fda9279dSmrg	const char *drivernames[2][2] = {
989fda9279dSmrg		{ "nouveau", "nouveau" },
990fda9279dSmrg		{ "nouveau_vieux", "nouveau_vieux" }
991fda9279dSmrg	};
992fda9279dSmrg
993fda9279dSmrg	if (pNv->AccelMethod != EXA)
994fda9279dSmrg		return FALSE;
995fda9279dSmrg
996fda9279dSmrg	if (pNv->Architecture >= NV_ARCH_30)
997fda9279dSmrg		dri2.driverNames = drivernames[0];
998fda9279dSmrg	else
999fda9279dSmrg		dri2.driverNames = drivernames[1];
1000fda9279dSmrg	dri2.numDrivers = 2;
1001fda9279dSmrg	dri2.driverName = dri2.driverNames[0];
1002fda9279dSmrg
1003fda9279dSmrg	dri2.fd = pNv->dev->fd;
1004fda9279dSmrg	dri2.deviceName = pNv->drm_device_name;
1005fda9279dSmrg
1006fda9279dSmrg	dri2.version = DRI2INFOREC_VERSION;
1007fda9279dSmrg	dri2.CreateBuffer = nouveau_dri2_create_buffer;
1008fda9279dSmrg	dri2.DestroyBuffer = nouveau_dri2_destroy_buffer;
1009fda9279dSmrg	dri2.CopyRegion = nouveau_dri2_copy_region;
1010fda9279dSmrg	dri2.ScheduleSwap = nouveau_dri2_schedule_swap;
1011fda9279dSmrg	dri2.ScheduleWaitMSC = nouveau_dri2_schedule_wait;
1012fda9279dSmrg	dri2.GetMSC = nouveau_dri2_get_msc;
1013fda9279dSmrg
1014fda9279dSmrg#if DRI2INFOREC_VERSION >= 6
1015fda9279dSmrg	dri2.SwapLimitValidate = nouveau_dri2_swap_limit_validate;
1016fda9279dSmrg#endif
1017fda9279dSmrg
1018fda9279dSmrg#if DRI2INFOREC_VERSION >= 7
1019fda9279dSmrg	dri2.version = 7;
1020fda9279dSmrg	dri2.GetParam = NULL;
1021fda9279dSmrg#endif
1022fda9279dSmrg
1023fda9279dSmrg#if DRI2INFOREC_VERSION >= 9
1024fda9279dSmrg	dri2.version = 9;
1025fda9279dSmrg	dri2.CreateBuffer2 = nouveau_dri2_create_buffer2;
1026fda9279dSmrg	dri2.DestroyBuffer2 = nouveau_dri2_destroy_buffer2;
1027fda9279dSmrg	dri2.CopyRegion2 = nouveau_dri2_copy_region2;
1028fda9279dSmrg#endif
1029fda9279dSmrg	return DRI2ScreenInit(pScreen, &dri2);
1030fda9279dSmrg}
1031fda9279dSmrg
1032fda9279dSmrgvoid
1033fda9279dSmrgnouveau_dri2_fini(ScreenPtr pScreen)
1034fda9279dSmrg{
1035fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1036fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
1037fda9279dSmrg	if (pNv->AccelMethod == EXA)
1038fda9279dSmrg		DRI2CloseScreen(pScreen);
1039fda9279dSmrg}
104016ee1e9aSmrg
104116ee1e9aSmrg#ifdef DRI3
1042dd52494dSmrgstatic int is_render_node(int fd)
104316ee1e9aSmrg{
1044dd52494dSmrg	struct stat st;
1045dd52494dSmrg	if (fstat(fd, &st))
104616ee1e9aSmrg		return 0;
104716ee1e9aSmrg
1048dd52494dSmrg	if (!S_ISCHR(st.st_mode))
104916ee1e9aSmrg		return 0;
105016ee1e9aSmrg
1051dd52494dSmrg	return st.st_rdev & 0x80;
105216ee1e9aSmrg  }
105316ee1e9aSmrg
105416ee1e9aSmrgstatic int
105516ee1e9aSmrgnouveau_dri3_open(ScreenPtr screen, RRProviderPtr provider, int *out)
105616ee1e9aSmrg{
105716ee1e9aSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
105816ee1e9aSmrg	NVPtr pNv = NVPTR(pScrn);
105916ee1e9aSmrg	int fd = -1;
106016ee1e9aSmrg
106116ee1e9aSmrg#ifdef O_CLOEXEC
106216ee1e9aSmrg	fd = open(pNv->render_node, O_RDWR | O_CLOEXEC);
106316ee1e9aSmrg#endif
106416ee1e9aSmrg	if (fd < 0)
106516ee1e9aSmrg		fd = open(pNv->render_node, O_RDWR);
106616ee1e9aSmrg	if (fd < 0)
106716ee1e9aSmrg		return -BadAlloc;
106816ee1e9aSmrg
1069dd52494dSmrg	if (!is_render_node(fd)) {
107016ee1e9aSmrg		drm_magic_t magic;
107116ee1e9aSmrg
107216ee1e9aSmrg		if (drmGetMagic(fd, &magic) || drmAuthMagic(pNv->dev->fd, magic)) {
107316ee1e9aSmrg			close(fd);
107416ee1e9aSmrg			return -BadMatch;
107516ee1e9aSmrg		}
107616ee1e9aSmrg	}
107716ee1e9aSmrg
107816ee1e9aSmrg	*out = fd;
107916ee1e9aSmrg	return Success;
108016ee1e9aSmrg}
108116ee1e9aSmrg
108216ee1e9aSmrgstatic PixmapPtr nouveau_dri3_pixmap_from_fd(ScreenPtr screen, int fd, CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp)
108316ee1e9aSmrg{
108416ee1e9aSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
108516ee1e9aSmrg	NVPtr pNv = NVPTR(pScrn);
108616ee1e9aSmrg	PixmapPtr pixmap;
108716ee1e9aSmrg	struct nouveau_bo *bo = NULL;
108816ee1e9aSmrg	struct nouveau_pixmap *nvpix;
108916ee1e9aSmrg
1090dd52494dSmrg	if (depth < 8 || depth > 32)
109116ee1e9aSmrg		return NULL;
109216ee1e9aSmrg
109316ee1e9aSmrg	pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
109416ee1e9aSmrg	if (!pixmap)
109516ee1e9aSmrg		return NULL;
109616ee1e9aSmrg
1097dd52494dSmrg	if (pixmap->drawable.bitsPerPixel % 8)
1098dd52494dSmrg		goto free_pixmap;
1099dd52494dSmrg
110016ee1e9aSmrg	if (!screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL))
110116ee1e9aSmrg		goto free_pixmap;
110216ee1e9aSmrg
110316ee1e9aSmrg	if (nouveau_bo_prime_handle_ref(pNv->dev, fd, &bo))
110416ee1e9aSmrg		goto free_pixmap;
110516ee1e9aSmrg
110616ee1e9aSmrg	nvpix = nouveau_pixmap(pixmap);
110716ee1e9aSmrg	nouveau_bo_ref(NULL, &nvpix->bo);
110816ee1e9aSmrg	nvpix->bo = bo;
110916ee1e9aSmrg	nvpix->shared = (bo->flags & NOUVEAU_BO_APER) == NOUVEAU_BO_GART;
111016ee1e9aSmrg	return pixmap;
111116ee1e9aSmrg
111216ee1e9aSmrgfree_pixmap:
111333adc6acSmrg	dixDestroyPixmap(pixmap, 0);
111416ee1e9aSmrg	return NULL;
111516ee1e9aSmrg}
111616ee1e9aSmrg
111716ee1e9aSmrgstatic int nouveau_dri3_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
111816ee1e9aSmrg{
111916ee1e9aSmrg	struct nouveau_bo *bo = nouveau_pixmap_bo(pixmap);
112016ee1e9aSmrg	int fd;
112116ee1e9aSmrg
112216ee1e9aSmrg	if (!bo || nouveau_bo_set_prime(bo, &fd) < 0)
112316ee1e9aSmrg		return -EINVAL;
112416ee1e9aSmrg
112516ee1e9aSmrg	*stride = pixmap->devKind;
112616ee1e9aSmrg	*size = bo->size;
112716ee1e9aSmrg	return fd;
112816ee1e9aSmrg}
112916ee1e9aSmrg
113016ee1e9aSmrgstatic dri3_screen_info_rec nouveau_dri3_screen_info = {
113116ee1e9aSmrg        .version = DRI3_SCREEN_INFO_VERSION,
113216ee1e9aSmrg
113316ee1e9aSmrg        .open = nouveau_dri3_open,
113416ee1e9aSmrg        .pixmap_from_fd = nouveau_dri3_pixmap_from_fd,
113516ee1e9aSmrg        .fd_from_pixmap = nouveau_dri3_fd_from_pixmap
113616ee1e9aSmrg};
113716ee1e9aSmrg#endif
113816ee1e9aSmrg
113916ee1e9aSmrgBool
114016ee1e9aSmrgnouveau_dri3_screen_init(ScreenPtr screen)
114116ee1e9aSmrg{
114216ee1e9aSmrg#ifdef DRI3
114316ee1e9aSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
114416ee1e9aSmrg	NVPtr pNv = NVPTR(pScrn);
114516ee1e9aSmrg	char *buf;
114616ee1e9aSmrg
1147dd52494dSmrg	if (is_render_node(pNv->dev->fd))
114816ee1e9aSmrg		return TRUE;
114916ee1e9aSmrg
115016ee1e9aSmrg	buf = drmGetRenderDeviceNameFromFd(pNv->dev->fd);
1151dd52494dSmrg	if (buf) {
115216ee1e9aSmrg		pNv->render_node = buf;
115316ee1e9aSmrg		if (dri3_screen_init(screen, &nouveau_dri3_screen_info)) {
115416ee1e9aSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
115516ee1e9aSmrg				   "DRI3 on EXA enabled\n");
115616ee1e9aSmrg			return TRUE;
115716ee1e9aSmrg		}
115816ee1e9aSmrg		else {
115916ee1e9aSmrg			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
116016ee1e9aSmrg				   "DRI3 on EXA initialization failed\n");
116116ee1e9aSmrg			return FALSE;
116216ee1e9aSmrg		}
116316ee1e9aSmrg	} else
116416ee1e9aSmrg		free(buf);
116516ee1e9aSmrg#endif
116616ee1e9aSmrg
116716ee1e9aSmrg        return TRUE;
116816ee1e9aSmrg}
1169