radeon_dri2.c revision 0974d292
1/*
2 * Copyright 2008 Kristian Høgsberg
3 * Copyright 2008 Jérôme Glisse
4 *
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation on the rights to use, copy, modify, merge,
11 * publish, distribute, sublicense, and/or sell copies of the Software,
12 * and to permit persons to whom the Software is furnished to do so,
13 * subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23 * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <fcntl.h>
35#include <errno.h>
36
37#include "radeon.h"
38#include "radeon_dri2.h"
39#include "radeon_version.h"
40
41#ifdef RADEON_DRI2
42
43#include "radeon_bo_gem.h"
44
45#if DRI2INFOREC_VERSION >= 1
46#define USE_DRI2_1_1_0
47#endif
48
49#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0, 0)
50typedef DRI2BufferPtr BufferPtr;
51#else
52typedef DRI2Buffer2Ptr BufferPtr;
53#endif
54
55struct dri2_buffer_priv {
56    PixmapPtr   pixmap;
57    unsigned int attachment;
58    unsigned int refcnt;
59};
60
61
62#ifndef USE_DRI2_1_1_0
63static BufferPtr
64radeon_dri2_create_buffers(DrawablePtr drawable,
65                           unsigned int *attachments,
66                           int count)
67{
68    ScreenPtr pScreen = drawable->pScreen;
69    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
70    RADEONInfoPtr info = RADEONPTR(pScrn);
71    BufferPtr buffers;
72    struct dri2_buffer_priv *privates;
73    PixmapPtr pixmap, depth_pixmap;
74    struct radeon_exa_pixmap_priv *driver_priv;
75    int i, r;
76    int flags = 0;
77
78    buffers = calloc(count, sizeof *buffers);
79    if (buffers == NULL) {
80        return NULL;
81    }
82    privates = calloc(count, sizeof(struct dri2_buffer_priv));
83    if (privates == NULL) {
84        free(buffers);
85        return NULL;
86    }
87
88    depth_pixmap = NULL;
89    for (i = 0; i < count; i++) {
90        if (attachments[i] == DRI2BufferFrontLeft) {
91            if (drawable->type == DRAWABLE_PIXMAP) {
92                pixmap = (Pixmap*)drawable;
93            } else {
94                pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable);
95            }
96            pixmap->refcnt++;
97        } else if (attachments[i] == DRI2BufferStencil && depth_pixmap) {
98            pixmap = depth_pixmap;
99            pixmap->refcnt++;
100        } else {
101	    /* tile the back buffer */
102	    switch(attachments[i]) {
103	    case DRI2BufferDepth:
104	    case DRI2BufferDepthStencil:
105		if (info->ChipFamily >= CHIP_FAMILY_R600)
106		    /* macro is the preferred setting, but the 2D detiling for software
107		     * fallbacks in mesa still has issues on some configurations
108		     */
109		    flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
110		else
111		    flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO;
112		break;
113	    case DRI2BufferBackLeft:
114	    case DRI2BufferBackRight:
115	    case DRI2BufferFakeFrontLeft:
116	    case DRI2BufferFakeFrontRight:
117		if (info->ChipFamily >= CHIP_FAMILY_R600)
118		    /* macro is the preferred setting, but the 2D detiling for software
119		     * fallbacks in mesa still has issues on some configurations
120		     */
121		    flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
122		else
123		    flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
124		break;
125	    default:
126		flags = 0;
127	    }
128	    pixmap = (*pScreen->CreatePixmap)(pScreen,
129                                              drawable->width,
130                                              drawable->height,
131                                              drawable->depth,
132                                              flags);
133        }
134
135        if (attachments[i] == DRI2BufferDepth) {
136            depth_pixmap = pixmap;
137        }
138	info->exa_force_create = TRUE;
139	exaMoveInPixmap(pixmap);
140	info->exa_force_create = FALSE;
141        driver_priv = exaGetPixmapDriverPrivate(pixmap);
142	r = radeon_gem_get_kernel_name(driver_priv->bo, &buffers[i].name);
143	if (r)
144		return r;
145
146        buffers[i].attachment = attachments[i];
147        buffers[i].pitch = pixmap->devKind;
148        buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8;
149        buffers[i].driverPrivate = &privates[i];
150        buffers[i].flags = 0;
151        privates[i].pixmap = pixmap;
152        privates[i].attachment = attachments[i];
153    }
154    return buffers;
155}
156#else
157static BufferPtr
158radeon_dri2_create_buffer(DrawablePtr drawable,
159                          unsigned int attachment,
160                          unsigned int format)
161{
162    ScreenPtr pScreen = drawable->pScreen;
163    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
164    RADEONInfoPtr info = RADEONPTR(pScrn);
165    BufferPtr buffers;
166    struct dri2_buffer_priv *privates;
167    PixmapPtr pixmap, depth_pixmap;
168    struct radeon_exa_pixmap_priv *driver_priv;
169    int r;
170    int flags;
171
172    buffers = calloc(1, sizeof *buffers);
173    if (buffers == NULL) {
174        return NULL;
175    }
176    privates = calloc(1, sizeof(struct dri2_buffer_priv));
177    if (privates == NULL) {
178        free(buffers);
179        return NULL;
180    }
181
182    depth_pixmap = NULL;
183
184    if (attachment == DRI2BufferFrontLeft) {
185        if (drawable->type == DRAWABLE_PIXMAP) {
186            pixmap = (PixmapPtr)drawable;
187        } else {
188            pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable);
189        }
190        pixmap->refcnt++;
191    } else if (attachment == DRI2BufferStencil && depth_pixmap) {
192        pixmap = depth_pixmap;
193        pixmap->refcnt++;
194    } else {
195	/* tile the back buffer */
196	switch(attachment) {
197	case DRI2BufferDepth:
198	case DRI2BufferDepthStencil:
199	    /* macro is the preferred setting, but the 2D detiling for software
200	     * fallbacks in mesa still has issues on some configurations
201	     */
202	    if (info->ChipFamily >= CHIP_FAMILY_R600)
203		flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
204	    else
205		flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO;
206	    break;
207	case DRI2BufferBackLeft:
208	case DRI2BufferBackRight:
209	case DRI2BufferFakeFrontLeft:
210	case DRI2BufferFakeFrontRight:
211	    if (info->ChipFamily >= CHIP_FAMILY_R600)
212		/* macro is the preferred setting, but the 2D detiling for software
213		 * fallbacks in mesa still has issues on some configurations
214		 */
215		flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
216	    else
217		flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
218	    break;
219	default:
220	    flags = 0;
221	}
222        pixmap = (*pScreen->CreatePixmap)(pScreen,
223                drawable->width,
224                drawable->height,
225                (format != 0)?format:drawable->depth,
226                flags);
227    }
228
229    if (attachment == DRI2BufferDepth) {
230        depth_pixmap = pixmap;
231    }
232    info->exa_force_create = TRUE;
233    exaMoveInPixmap(pixmap);
234    info->exa_force_create = FALSE;
235    driver_priv = exaGetPixmapDriverPrivate(pixmap);
236    r = radeon_gem_get_kernel_name(driver_priv->bo, &buffers->name);
237    if (r)
238	    return NULL;
239
240    buffers->attachment = attachment;
241    buffers->pitch = pixmap->devKind;
242    buffers->cpp = pixmap->drawable.bitsPerPixel / 8;
243    buffers->driverPrivate = privates;
244    buffers->format = format;
245    buffers->flags = 0; /* not tiled */
246    privates->pixmap = pixmap;
247    privates->attachment = attachment;
248    privates->refcnt = 1;
249
250    return buffers;
251}
252#endif
253
254#ifndef USE_DRI2_1_1_0
255static void
256radeon_dri2_destroy_buffers(DrawablePtr drawable,
257                            BufferPtr buffers,
258                            int count)
259{
260    ScreenPtr pScreen = drawable->pScreen;
261    struct dri2_buffer_priv *private;
262    int i;
263
264    for (i = 0; i < count; i++) {
265        private = buffers[i].driverPrivate;
266        (*pScreen->DestroyPixmap)(private->pixmap);
267    }
268    if (buffers) {
269        free(buffers[0].driverPrivate);
270        free(buffers);
271    }
272}
273#else
274static void
275radeon_dri2_destroy_buffer(DrawablePtr drawable, BufferPtr buffers)
276{
277    if(buffers)
278    {
279        ScreenPtr pScreen = drawable->pScreen;
280        struct dri2_buffer_priv *private = buffers->driverPrivate;
281
282        /* Trying to free an already freed buffer is unlikely to end well */
283        if (private->refcnt == 0) {
284            ScrnInfoPtr scrn = xf86Screens[pScreen->myNum];
285
286            xf86DrvMsg(scrn->scrnIndex, X_WARNING,
287                       "Attempted to destroy previously destroyed buffer.\
288 This is a programming error\n");
289            return;
290        }
291
292        private->refcnt--;
293        if (private->refcnt == 0)
294        {
295            (*pScreen->DestroyPixmap)(private->pixmap);
296
297            free(buffers->driverPrivate);
298            free(buffers);
299        }
300    }
301}
302#endif
303
304static void
305radeon_dri2_copy_region(DrawablePtr drawable,
306                        RegionPtr region,
307                        BufferPtr dest_buffer,
308                        BufferPtr src_buffer)
309{
310    struct dri2_buffer_priv *src_private = src_buffer->driverPrivate;
311    struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate;
312    ScreenPtr pScreen = drawable->pScreen;
313    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
314    DrawablePtr src_drawable;
315    DrawablePtr dst_drawable;
316    RegionPtr copy_clip;
317    GCPtr gc;
318    RADEONInfoPtr info = RADEONPTR(pScrn);
319    Bool vsync;
320
321    if (src_private->attachment == DRI2BufferFrontLeft) {
322        src_drawable = drawable;
323    } else {
324        src_drawable = &src_private->pixmap->drawable;
325    }
326    if (dst_private->attachment == DRI2BufferFrontLeft) {
327        dst_drawable = drawable;
328    } else {
329        dst_drawable = &dst_private->pixmap->drawable;
330    }
331    gc = GetScratchGC(dst_drawable->depth, pScreen);
332    copy_clip = REGION_CREATE(pScreen, NULL, 0);
333    REGION_COPY(pScreen, copy_clip, region);
334    (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0);
335    ValidateGC(dst_drawable, gc);
336
337    /* If this is a full buffer swap or frontbuffer flush, throttle on the
338     * previous one
339     */
340    if (dst_private->attachment == DRI2BufferFrontLeft) {
341	if (REGION_NUM_RECTS(region) == 1) {
342	    BoxPtr extents = REGION_EXTENTS(pScreen, region);
343
344	    if (extents->x1 == 0 && extents->y1 == 0 &&
345		extents->x2 == drawable->width &&
346		extents->y2 == drawable->height) {
347		struct radeon_exa_pixmap_priv *exa_priv =
348		    exaGetPixmapDriverPrivate(dst_private->pixmap);
349
350		if (exa_priv && exa_priv->bo)
351		    radeon_bo_wait(exa_priv->bo);
352	    }
353	}
354    }
355
356    vsync = info->accel_state->vsync;
357    info->accel_state->vsync = TRUE;
358
359    (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc,
360                         0, 0, drawable->width, drawable->height, 0, 0);
361
362    info->accel_state->vsync = vsync;
363
364    FreeScratchGC(gc);
365}
366
367
368#if DRI2INFOREC_VERSION >= 4
369
370enum DRI2FrameEventType {
371    DRI2_SWAP,
372    DRI2_FLIP,
373    DRI2_WAITMSC,
374};
375
376typedef struct _DRI2FrameEvent {
377    XID drawable_id;
378    ClientPtr client;
379    int client_index;
380    enum DRI2FrameEventType type;
381    int frame;
382
383    /* for swaps & flips only */
384    DRI2SwapEventPtr event_complete;
385    void *event_data;
386    DRI2BufferPtr front;
387    DRI2BufferPtr back;
388} DRI2FrameEventRec, *DRI2FrameEventPtr;
389
390static void
391radeon_dri2_ref_buffer(BufferPtr buffer)
392{
393    struct dri2_buffer_priv *private = buffer->driverPrivate;
394    private->refcnt++;
395}
396
397static void
398radeon_dri2_unref_buffer(BufferPtr buffer)
399{
400    if (buffer) {
401        struct dri2_buffer_priv *private = buffer->driverPrivate;
402        radeon_dri2_destroy_buffer(&(private->pixmap->drawable), buffer);
403    }
404}
405
406void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
407                                     unsigned int tv_usec, void *event_data)
408{
409    DRI2FrameEventPtr event = event_data;
410    DrawablePtr drawable;
411    ClientPtr client;
412    ScreenPtr screen;
413    ScrnInfoPtr scrn;
414    int status;
415    int swap_type;
416    BoxRec box;
417    RegionRec region;
418
419    status = dixLookupDrawable(&drawable, event->drawable_id, serverClient,
420                               M_ANY, DixWriteAccess);
421    if (status != Success) {
422        radeon_dri2_unref_buffer(event->front);
423        radeon_dri2_unref_buffer(event->back);
424        free(event);
425        return;
426    }
427
428    screen = drawable->pScreen;
429    scrn = xf86Screens[screen->myNum];
430
431    /* event->client may have quit between submitting a request
432     * and this callback being triggered.
433     *
434     * Check our saved client pointer against the client in the saved client
435     * slot.  This will catch almost all cases where the client that requested
436     * SwapBuffers has gone away, and will guarantee that there is at least a
437     * valid client to write the BufferSwapComplete event to.
438     */
439    client = event->client == clients[event->client_index] ?
440            event->client : NULL;
441
442    switch (event->type) {
443    case DRI2_FLIP:
444    case DRI2_SWAP:
445        box.x1 = 0;
446        box.y1 = 0;
447        box.x2 = drawable->width;
448        box.y2 = drawable->height;
449        REGION_INIT(pScreen, &region, &box, 0);
450        radeon_dri2_copy_region(drawable, &region, event->front, event->back);
451        swap_type = DRI2_BLIT_COMPLETE;
452
453        DRI2SwapComplete(client, drawable, frame, tv_sec, tv_usec,
454                swap_type, event->event_complete, event->event_data);
455
456        radeon_dri2_unref_buffer(event->front);
457        radeon_dri2_unref_buffer(event->back);
458        break;
459    case DRI2_WAITMSC:
460        DRI2WaitMSCComplete(client, drawable, frame, tv_sec, tv_usec);
461        break;
462    default:
463        /* Unknown type */
464        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
465                "%s: unknown vblank event received\n", __func__);
466        break;
467    }
468
469    free(event);
470}
471
472static int radeon_dri2_drawable_crtc(DrawablePtr pDraw)
473{
474    ScreenPtr pScreen = pDraw->pScreen;
475    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
476    xf86CrtcPtr crtc;
477    int crtc_id = -1;
478
479    crtc = radeon_pick_best_crtc(pScrn,
480				 pDraw->x,
481				 pDraw->x + pDraw->width,
482				 pDraw->y,
483				 pDraw->y + pDraw->height);
484
485    /* Make sure the CRTC is valid and this is the real front buffer */
486    if (crtc != NULL && !crtc->rotatedData) {
487        crtc_id = drmmode_get_crtc_id(crtc);
488    }
489    return crtc_id;
490}
491
492/*
493 * Get current frame count and frame count timestamp, based on drawable's
494 * crtc.
495 */
496static int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
497{
498    ScreenPtr screen = draw->pScreen;
499    ScrnInfoPtr scrn = xf86Screens[screen->myNum];
500    RADEONInfoPtr info = RADEONPTR(scrn);
501    drmVBlank vbl;
502    int ret;
503    int crtc= radeon_dri2_drawable_crtc(draw);
504
505    /* Drawable not displayed, make up a value */
506    if (crtc == -1) {
507        *ust = 0;
508        *msc = 0;
509        return TRUE;
510    }
511    vbl.request.type = DRM_VBLANK_RELATIVE;
512    if (crtc > 0)
513        vbl.request.type |= DRM_VBLANK_SECONDARY;
514    vbl.request.sequence = 0;
515
516    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
517    if (ret) {
518        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
519                "get vblank counter failed: %s\n", strerror(errno));
520        return FALSE;
521    }
522
523    *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec;
524    *msc = vbl.reply.sequence;
525
526    return TRUE;
527}
528
529/*
530 * Request a DRM event when the requested conditions will be satisfied.
531 *
532 * We need to handle the event and ask the server to wake up the client when
533 * we receive it.
534 */
535static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw,
536                                         CARD64 target_msc, CARD64 divisor,
537                                         CARD64 remainder)
538{
539    ScreenPtr screen = draw->pScreen;
540    ScrnInfoPtr scrn = xf86Screens[screen->myNum];
541    RADEONInfoPtr info = RADEONPTR(scrn);
542    DRI2FrameEventPtr wait_info;
543    drmVBlank vbl;
544    int ret, crtc = radeon_dri2_drawable_crtc(draw);
545    CARD64 current_msc;
546
547    /* Truncate to match kernel interfaces; means occasional overflow
548     * misses, but that's generally not a big deal */
549    target_msc &= 0xffffffff;
550    divisor &= 0xffffffff;
551    remainder &= 0xffffffff;
552
553    /* Drawable not visible, return immediately */
554    if (crtc == -1)
555        goto out_complete;
556
557    wait_info = calloc(1, sizeof(DRI2FrameEventRec));
558    if (!wait_info)
559        goto out_complete;
560
561    wait_info->drawable_id = draw->id;
562    wait_info->client = client;
563    wait_info->client_index = client->index;
564    wait_info->type = DRI2_WAITMSC;
565
566    /* Get current count */
567    vbl.request.type = DRM_VBLANK_RELATIVE;
568    if (crtc > 0)
569        vbl.request.type |= DRM_VBLANK_SECONDARY;
570    vbl.request.sequence = 0;
571    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
572    if (ret) {
573        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
574                "get vblank counter failed: %s\n", strerror(errno));
575        goto out_complete;
576    }
577
578    current_msc = vbl.reply.sequence;
579
580    /*
581     * If divisor is zero, or current_msc is smaller than target_msc,
582     * we just need to make sure target_msc passes  before waking up the
583     * client.
584     */
585    if (divisor == 0 || current_msc < target_msc) {
586        /* If target_msc already reached or passed, set it to
587         * current_msc to ensure we return a reasonable value back
588         * to the caller. This keeps the client from continually
589         * sending us MSC targets from the past by forcibly updating
590         * their count on this call.
591         */
592        if (current_msc >= target_msc)
593            target_msc = current_msc;
594        vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
595        if (crtc > 0)
596            vbl.request.type |= DRM_VBLANK_SECONDARY;
597        vbl.request.sequence = target_msc;
598        vbl.request.signal = (unsigned long)wait_info;
599        ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
600        if (ret) {
601            xf86DrvMsg(scrn->scrnIndex, X_WARNING,
602                    "get vblank counter failed: %s\n", strerror(errno));
603            goto out_complete;
604        }
605
606        wait_info->frame = vbl.reply.sequence;
607        DRI2BlockClient(client, draw);
608        return TRUE;
609    }
610
611    /*
612     * If we get here, target_msc has already passed or we don't have one,
613     * so we queue an event that will satisfy the divisor/remainder equation.
614     */
615    vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
616    if (crtc > 0)
617        vbl.request.type |= DRM_VBLANK_SECONDARY;
618
619    vbl.request.sequence = current_msc - (current_msc % divisor) +
620        remainder;
621
622    /*
623     * If calculated remainder is larger than requested remainder,
624     * it means we've passed the last point where
625     * seq % divisor == remainder, so we need to wait for the next time
626     * that will happen.
627     */
628    if ((current_msc % divisor) >= remainder)
629        vbl.request.sequence += divisor;
630
631    vbl.request.signal = (unsigned long)wait_info;
632    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
633    if (ret) {
634        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
635                "get vblank counter failed: %s\n", strerror(errno));
636        goto out_complete;
637    }
638
639    wait_info->frame = vbl.reply.sequence;
640    DRI2BlockClient(client, draw);
641
642    return TRUE;
643
644out_complete:
645    DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
646    return TRUE;
647}
648
649/*
650 * ScheduleSwap is responsible for requesting a DRM vblank event for the
651 * appropriate frame.
652 *
653 * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
654 * the vblank requested can simply be the last queued swap frame + the swap
655 * interval for the drawable.
656 *
657 * In the case of a page flip, we request an event for the last queued swap
658 * frame + swap interval - 1, since we'll need to queue the flip for the frame
659 * immediately following the received event.
660 *
661 * The client will be blocked if it tries to perform further GL commands
662 * after queueing a swap, though in the Intel case after queueing a flip, the
663 * client is free to queue more commands; they'll block in the kernel if
664 * they access buffers busy with the flip.
665 *
666 * When the swap is complete, the driver should call into the server so it
667 * can send any swap complete events that have been requested.
668 */
669static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
670                                     DRI2BufferPtr front, DRI2BufferPtr back,
671                                     CARD64 *target_msc, CARD64 divisor,
672                                     CARD64 remainder, DRI2SwapEventPtr func,
673                                     void *data)
674{
675    ScreenPtr screen = draw->pScreen;
676    ScrnInfoPtr scrn = xf86Screens[screen->myNum];
677    RADEONInfoPtr info = RADEONPTR(scrn);
678    drmVBlank vbl;
679    int ret, crtc= radeon_dri2_drawable_crtc(draw), flip = 0;
680    DRI2FrameEventPtr swap_info;
681    enum DRI2FrameEventType swap_type = DRI2_SWAP;
682    CARD64 current_msc;
683    BoxRec box;
684    RegionRec region;
685
686    /* Truncate to match kernel interfaces; means occasional overflow
687     * misses, but that's generally not a big deal */
688    *target_msc &= 0xffffffff;
689    divisor &= 0xffffffff;
690    remainder &= 0xffffffff;
691
692    swap_info = calloc(1, sizeof(DRI2FrameEventRec));
693
694    /* radeon_dri2_frame_event_handler will get called some unknown time in the
695     * future with these buffers.  Take a reference to ensure that they won't
696     * get destroyed before then.
697     */
698    radeon_dri2_ref_buffer(front);
699    radeon_dri2_ref_buffer(back);
700
701    /* Drawable not displayed... just complete the swap */
702    if (crtc == -1 || !swap_info)
703        goto blit_fallback;
704
705    swap_info->drawable_id = draw->id;
706    swap_info->client = client;
707    swap_info->client_index = client->index;
708    swap_info->event_complete = func;
709    swap_info->event_data = data;
710    swap_info->front = front;
711    swap_info->back = back;
712
713    /* Get current count */
714    vbl.request.type = DRM_VBLANK_RELATIVE;
715    if (crtc > 0)
716        vbl.request.type |= DRM_VBLANK_SECONDARY;
717    vbl.request.sequence = 0;
718    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
719    if (ret) {
720        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
721                "first get vblank counter failed: %s\n",
722                strerror(errno));
723        goto blit_fallback;
724    }
725
726    current_msc = vbl.reply.sequence;
727    swap_info->type = swap_type;
728
729    /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
730     * Do it early, so handling of different timing constraints
731     * for divisor, remainder and msc vs. target_msc works.
732     */
733    if (*target_msc > 0)
734        *target_msc -= flip;
735
736    /*
737     * If divisor is zero, or current_msc is smaller than target_msc
738     * we just need to make sure target_msc passes before initiating
739     * the swap.
740     */
741    if (divisor == 0 || current_msc < *target_msc) {
742        vbl.request.type =  DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
743        if (crtc > 0)
744            vbl.request.type |= DRM_VBLANK_SECONDARY;
745
746        /* If non-pageflipping, but blitting/exchanging, we need to use
747         * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
748         * on.
749         */
750        if (flip == 0)
751            vbl.request.type |= DRM_VBLANK_NEXTONMISS;
752        if (crtc > 0)
753            vbl.request.type |= DRM_VBLANK_SECONDARY;
754
755        /* If target_msc already reached or passed, set it to
756         * current_msc to ensure we return a reasonable value back
757         * to the caller. This makes swap_interval logic more robust.
758         */
759        if (current_msc >= *target_msc)
760            *target_msc = current_msc;
761
762        vbl.request.sequence = *target_msc;
763        vbl.request.signal = (unsigned long)swap_info;
764        ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
765        if (ret) {
766            xf86DrvMsg(scrn->scrnIndex, X_WARNING,
767                    "divisor 0 get vblank counter failed: %s\n",
768                    strerror(errno));
769            goto blit_fallback;
770        }
771
772        *target_msc = vbl.reply.sequence + flip;
773        swap_info->frame = *target_msc;
774
775        return TRUE;
776    }
777
778    /*
779     * If we get here, target_msc has already passed or we don't have one,
780     * and we need to queue an event that will satisfy the divisor/remainder
781     * equation.
782     */
783    vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
784    if (flip == 0)
785        vbl.request.type |= DRM_VBLANK_NEXTONMISS;
786    if (crtc > 0)
787        vbl.request.type |= DRM_VBLANK_SECONDARY;
788
789    vbl.request.sequence = current_msc - (current_msc % divisor) +
790        remainder;
791
792    /*
793     * If the calculated deadline vbl.request.sequence is smaller than
794     * or equal to current_msc, it means we've passed the last point
795     * when effective onset frame seq could satisfy
796     * seq % divisor == remainder, so we need to wait for the next time
797     * this will happen.
798
799     * This comparison takes the 1 frame swap delay in pageflipping mode
800     * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
801     * if we are blitting/exchanging instead of flipping.
802     */
803    if (vbl.request.sequence <= current_msc)
804        vbl.request.sequence += divisor;
805
806    /* Account for 1 frame extra pageflip delay if flip > 0 */
807    vbl.request.sequence -= flip;
808
809    vbl.request.signal = (unsigned long)swap_info;
810    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
811    if (ret) {
812        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
813                "final get vblank counter failed: %s\n",
814                strerror(errno));
815        goto blit_fallback;
816    }
817
818    /* Adjust returned value for 1 fame pageflip offset of flip > 0 */
819    *target_msc = vbl.reply.sequence + flip;
820    swap_info->frame = *target_msc;
821
822    return TRUE;
823
824blit_fallback:
825    box.x1 = 0;
826    box.y1 = 0;
827    box.x2 = draw->width;
828    box.y2 = draw->height;
829    REGION_INIT(pScreen, &region, &box, 0);
830
831    radeon_dri2_copy_region(draw, &region, front, back);
832
833    DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
834    if (swap_info)
835        free(swap_info);
836
837    radeon_dri2_unref_buffer(front);
838    radeon_dri2_unref_buffer(back);
839
840    *target_msc = 0; /* offscreen, so zero out target vblank count */
841    return TRUE;
842}
843
844#endif /* DRI2INFOREC_VERSION >= 4 */
845
846
847Bool
848radeon_dri2_screen_init(ScreenPtr pScreen)
849{
850    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
851    RADEONInfoPtr info = RADEONPTR(pScrn);
852    DRI2InfoRec dri2_info = { 0 };
853#if DRI2INFOREC_VERSION >= 4
854    const char *driverNames[1];
855#endif
856
857    if (!info->useEXA) {
858        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 requires EXA\n");
859        return FALSE;
860    }
861
862    info->dri2.device_name = drmGetDeviceNameFromFd(info->dri2.drm_fd);
863
864    if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) {
865        dri2_info.driverName = R600_DRIVER_NAME;
866    } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) {
867        dri2_info.driverName = R300_DRIVER_NAME;
868    } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) {
869        dri2_info.driverName = R200_DRIVER_NAME;
870    } else {
871        dri2_info.driverName = RADEON_DRIVER_NAME;
872    }
873    dri2_info.fd = info->dri2.drm_fd;
874    dri2_info.deviceName = info->dri2.device_name;
875#ifndef USE_DRI2_1_1_0
876    dri2_info.version = 1;
877    dri2_info.CreateBuffers = radeon_dri2_create_buffers;
878    dri2_info.DestroyBuffers = radeon_dri2_destroy_buffers;
879#else
880    dri2_info.version = DRI2INFOREC_VERSION;
881    dri2_info.CreateBuffer = radeon_dri2_create_buffer;
882    dri2_info.DestroyBuffer = radeon_dri2_destroy_buffer;
883#endif
884    dri2_info.CopyRegion = radeon_dri2_copy_region;
885
886#if DRI2INFOREC_VERSION >= 4
887    if (info->dri->pKernelDRMVersion->version_minor >= 4) {
888        dri2_info.version = 4;
889        dri2_info.ScheduleSwap = radeon_dri2_schedule_swap;
890        dri2_info.GetMSC = radeon_dri2_get_msc;
891        dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc;
892        dri2_info.numDrivers = 1;
893        dri2_info.driverNames = driverNames;
894        driverNames[0] = dri2_info.driverName;
895    } else {
896        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for sync extension\n");
897    }
898#endif
899
900    info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info);
901    return info->dri2.enabled;
902}
903
904void radeon_dri2_close_screen(ScreenPtr pScreen)
905{
906    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
907    RADEONInfoPtr info = RADEONPTR(pScrn);
908
909    DRI2CloseScreen(pScreen);
910    drmFree(info->dri2.device_name);
911}
912
913#endif
914