radeon_dri2.c revision 7821949a
1de2362d3Smrg/*
2de2362d3Smrg * Copyright 2008 Kristian Høgsberg
3de2362d3Smrg * Copyright 2008 Jérôme Glisse
4de2362d3Smrg *
5de2362d3Smrg * All Rights Reserved.
6de2362d3Smrg *
7de2362d3Smrg * Permission is hereby granted, free of charge, to any person obtaining
8de2362d3Smrg * a copy of this software and associated documentation files (the
9de2362d3Smrg * "Software"), to deal in the Software without restriction, including
10de2362d3Smrg * without limitation on the rights to use, copy, modify, merge,
11de2362d3Smrg * publish, distribute, sublicense, and/or sell copies of the Software,
12de2362d3Smrg * and to permit persons to whom the Software is furnished to do so,
13de2362d3Smrg * subject to the following conditions:
14de2362d3Smrg *
15de2362d3Smrg * The above copyright notice and this permission notice (including the
16de2362d3Smrg * next paragraph) shall be included in all copies or substantial
17de2362d3Smrg * portions of the Software.
18de2362d3Smrg *
19de2362d3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20de2362d3Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21de2362d3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22de2362d3Smrg * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23de2362d3Smrg * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24de2362d3Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25de2362d3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26de2362d3Smrg * DEALINGS IN THE SOFTWARE.
27de2362d3Smrg */
28de2362d3Smrg#ifdef HAVE_CONFIG_H
29de2362d3Smrg#include "config.h"
30de2362d3Smrg#endif
31de2362d3Smrg
32de2362d3Smrg#include <sys/types.h>
33de2362d3Smrg#include <sys/stat.h>
34de2362d3Smrg#include <fcntl.h>
35de2362d3Smrg#include <errno.h>
36de2362d3Smrg
377821949aSmrg#include "radeon.h"
387821949aSmrg#include "radeon_dri2.h"
39de2362d3Smrg#include "radeon_version.h"
40de2362d3Smrg
417821949aSmrg#if HAVE_LIST_H
427821949aSmrg#include "list.h"
437821949aSmrg#if !HAVE_XORG_LIST
447821949aSmrg#define xorg_list			list
457821949aSmrg#define xorg_list_init			list_init
467821949aSmrg#define xorg_list_add			list_add
477821949aSmrg#define xorg_list_del			list_del
487821949aSmrg#define xorg_list_for_each_entry	list_for_each_entry
497821949aSmrg#endif
507821949aSmrg#endif
51de2362d3Smrg
527821949aSmrg#ifdef RADEON_DRI2
53de2362d3Smrg
547821949aSmrg#include "radeon_bo_gem.h"
55de2362d3Smrg
567821949aSmrg#if DRI2INFOREC_VERSION >= 1
577821949aSmrg#define USE_DRI2_1_1_0
587821949aSmrg#endif
59de2362d3Smrg
607821949aSmrg#if DRI2INFOREC_VERSION >= 4 && HAVE_LIST_H
617821949aSmrg#define USE_DRI2_SCHEDULING
627821949aSmrg#endif
63de2362d3Smrg
647821949aSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0, 0)
65de2362d3Smrgtypedef DRI2BufferPtr BufferPtr;
667821949aSmrg#else
677821949aSmrgtypedef DRI2Buffer2Ptr BufferPtr;
687821949aSmrg#endif
69de2362d3Smrg
70de2362d3Smrgstruct dri2_buffer_priv {
71de2362d3Smrg    PixmapPtr   pixmap;
72de2362d3Smrg    unsigned int attachment;
73de2362d3Smrg    unsigned int refcnt;
74de2362d3Smrg};
75de2362d3Smrg
76de2362d3Smrg
777821949aSmrg#ifndef USE_DRI2_1_1_0
787821949aSmrgstatic BufferPtr
797821949aSmrgradeon_dri2_create_buffers(DrawablePtr drawable,
807821949aSmrg                           unsigned int *attachments,
817821949aSmrg                           int count)
827821949aSmrg{
837821949aSmrg    ScreenPtr pScreen = drawable->pScreen;
847821949aSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
857821949aSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
867821949aSmrg    BufferPtr buffers;
877821949aSmrg    struct dri2_buffer_priv *privates;
887821949aSmrg    PixmapPtr pixmap, depth_pixmap;
897821949aSmrg    struct radeon_exa_pixmap_priv *driver_priv;
907821949aSmrg    int i, r, need_enlarge = 0;
917821949aSmrg    int flags = 0;
927821949aSmrg    unsigned front_width;
937821949aSmrg    uint32_t tiling = 0;
940d16fef4Smrg
957821949aSmrg    pixmap = screen->GetScreenPixmap(screen);
967821949aSmrg    front_width = pixmap->drawable.width;
970d16fef4Smrg
987821949aSmrg    buffers = calloc(count, sizeof *buffers);
997821949aSmrg    if (buffers == NULL) {
1007821949aSmrg        return NULL;
1017821949aSmrg    }
1027821949aSmrg    privates = calloc(count, sizeof(struct dri2_buffer_priv));
1037821949aSmrg    if (privates == NULL) {
1047821949aSmrg        free(buffers);
1057821949aSmrg        return NULL;
1067821949aSmrg    }
1070d16fef4Smrg
1087821949aSmrg    depth_pixmap = NULL;
1097821949aSmrg    for (i = 0; i < count; i++) {
1107821949aSmrg        if (attachments[i] == DRI2BufferFrontLeft) {
1117821949aSmrg            if (drawable->type == DRAWABLE_PIXMAP) {
1127821949aSmrg                pixmap = (Pixmap*)drawable;
1137821949aSmrg            } else {
1147821949aSmrg                pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable);
1157821949aSmrg            }
1167821949aSmrg            pixmap->refcnt++;
1177821949aSmrg        } else if (attachments[i] == DRI2BufferStencil && depth_pixmap) {
1187821949aSmrg            pixmap = depth_pixmap;
1197821949aSmrg            pixmap->refcnt++;
1207821949aSmrg        } else {
1217821949aSmrg	    /* tile the back buffer */
1227821949aSmrg	    switch(attachments[i]) {
1237821949aSmrg	    case DRI2BufferDepth:
1247821949aSmrg		if (info->ChipFamily >= CHIP_FAMILY_R600)
1257821949aSmrg		    /* macro is the preferred setting, but the 2D detiling for software
1267821949aSmrg		     * fallbacks in mesa still has issues on some configurations
1277821949aSmrg		     */
1287821949aSmrg		    flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
1297821949aSmrg		else
1307821949aSmrg		    flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO;
1317821949aSmrg		if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON)
1327821949aSmrg		    flags |= RADEON_CREATE_PIXMAP_DEPTH;
1337821949aSmrg		break;
1347821949aSmrg	    case DRI2BufferDepthStencil:
1357821949aSmrg		if (info->ChipFamily >= CHIP_FAMILY_R600) {
1367821949aSmrg		    /* macro is the preferred setting, but the 2D detiling for software
1377821949aSmrg		     * fallbacks in mesa still has issues on some configurations
1387821949aSmrg		     */
1397821949aSmrg		    flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
1407821949aSmrg		    if (info->ChipFamily >= CHIP_FAMILY_CEDAR)
1417821949aSmrg			need_enlarge = 1;
1427821949aSmrg		} else
1437821949aSmrg		    flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO;
1447821949aSmrg		if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON)
1457821949aSmrg		    flags |= RADEON_CREATE_PIXMAP_DEPTH;
1467821949aSmrg		break;
1477821949aSmrg	    case DRI2BufferBackLeft:
1487821949aSmrg	    case DRI2BufferBackRight:
1497821949aSmrg	    case DRI2BufferFakeFrontLeft:
1507821949aSmrg	    case DRI2BufferFakeFrontRight:
1517821949aSmrg		if (info->ChipFamily >= CHIP_FAMILY_R600)
1527821949aSmrg		    /* macro is the preferred setting, but the 2D detiling for software
1537821949aSmrg		     * fallbacks in mesa still has issues on some configurations
1547821949aSmrg		     */
1557821949aSmrg		    flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
1567821949aSmrg		else
1577821949aSmrg		    flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
1587821949aSmrg		break;
1597821949aSmrg	    default:
1607821949aSmrg		flags = 0;
1617821949aSmrg	    }
1620d16fef4Smrg
1637821949aSmrg	    if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO)
1647821949aSmrg		tiling |= RADEON_TILING_MICRO;
1657821949aSmrg	    if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO)
1667821949aSmrg		tiling |= RADEON_TILING_MACRO;
1677821949aSmrg
1687821949aSmrg	    if (need_enlarge) {
1697821949aSmrg		/* evergreen uses separate allocations for depth and stencil
1707821949aSmrg		 * so we make an extra large depth buffer to cover stencil
1717821949aSmrg		 * as well.
1727821949aSmrg		 */
1737821949aSmrg		unsigned aligned_width = drawable->width;
1747821949aSmrg		unsigned width_align = drmmode_get_pitch_align(pScrn, drawable->depth / 8, tiling);
1757821949aSmrg		unsigned aligned_height;
1767821949aSmrg		unsigned height_align = drmmode_get_height_align(pScrn, tiling);
1777821949aSmrg		unsigned base_align = drmmode_get_base_align(pScrn, drawable->depth / 8, tiling);
1787821949aSmrg		unsigned pitch_bytes;
1797821949aSmrg		unsigned size;
1807821949aSmrg
1817821949aSmrg		if (aligned_width == front_width)
1827821949aSmrg		    aligned_width = pScrn->virtualX;
1837821949aSmrg		aligned_width = RADEON_ALIGN(aligned_width, width_align);
1847821949aSmrg		pitch_bytes = aligned_width * (drawable->depth / 8);
1857821949aSmrg		aligned_height = RADEON_ALIGN(drawable->height, height_align);
1867821949aSmrg		size = pitch_bytes * aligned_height;
1877821949aSmrg		size = RADEON_ALIGN(size, base_align);
1887821949aSmrg		/* add additional size for stencil */
1897821949aSmrg		size += aligned_width * aligned_height;
1907821949aSmrg		aligned_height = RADEON_ALIGN(size / pitch_bytes, height_align);
1917821949aSmrg
1927821949aSmrg		pixmap = (*pScreen->CreatePixmap)(pScreen,
1937821949aSmrg						  aligned_width,
1947821949aSmrg						  aligned_height,
1957821949aSmrg						  drawable->depth,
1967821949aSmrg						  flags);
1977821949aSmrg
1987821949aSmrg	    } else {
1997821949aSmrg		unsigned aligned_width = drawable->width;
2007821949aSmrg
2017821949aSmrg		if (aligned_width == front_width)
2027821949aSmrg		    aligned_width = pScrn->virtualX;
2037821949aSmrg
2047821949aSmrg		pixmap = (*pScreen->CreatePixmap)(pScreen,
2057821949aSmrg						  aligned_width,
2067821949aSmrg						  drawable->height,
2077821949aSmrg						  drawable->depth,
2087821949aSmrg						  flags);
2097821949aSmrg	    }
2107821949aSmrg        }
2110d16fef4Smrg
2127821949aSmrg        if (attachments[i] == DRI2BufferDepth) {
2137821949aSmrg            depth_pixmap = pixmap;
2147821949aSmrg        }
2157821949aSmrg	info->exa_force_create = TRUE;
2167821949aSmrg	exaMoveInPixmap(pixmap);
2177821949aSmrg	info->exa_force_create = FALSE;
2187821949aSmrg        driver_priv = exaGetPixmapDriverPrivate(pixmap);
2197821949aSmrg	if (!driver_priv ||
2207821949aSmrg	    radeon_gem_get_kernel_name(driver_priv->bo, &buffers[i].name) != 0) {
2217821949aSmrg	    int j;
2227821949aSmrg
2237821949aSmrg	    for (j = 0; j < i; j++)
2247821949aSmrg		(*pScreen->DestroyPixmap)(privates[j].pixmap);
2257821949aSmrg	    (*pScreen->DestroyPixmap)(pixmap);
2267821949aSmrg	    free(privates);
2277821949aSmrg	    free(buffers);
2287821949aSmrg	    return NULL;
2297821949aSmrg	}
2300d16fef4Smrg
2317821949aSmrg        buffers[i].attachment = attachments[i];
2327821949aSmrg        buffers[i].pitch = pixmap->devKind;
2337821949aSmrg        buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8;
2347821949aSmrg        buffers[i].driverPrivate = &privates[i];
2357821949aSmrg        buffers[i].flags = 0;
2367821949aSmrg        privates[i].pixmap = pixmap;
2377821949aSmrg        privates[i].attachment = attachments[i];
2380d16fef4Smrg    }
2397821949aSmrg    return buffers;
2400d16fef4Smrg}
2417821949aSmrg#else
242de2362d3Smrgstatic BufferPtr
2437821949aSmrgradeon_dri2_create_buffer(DrawablePtr drawable,
2447821949aSmrg                          unsigned int attachment,
2457821949aSmrg                          unsigned int format)
246de2362d3Smrg{
2477821949aSmrg    ScreenPtr pScreen = drawable->pScreen;
248de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
249de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
250de2362d3Smrg    BufferPtr buffers;
251de2362d3Smrg    struct dri2_buffer_priv *privates;
2527821949aSmrg    PixmapPtr pixmap, depth_pixmap;
2537821949aSmrg    struct radeon_exa_pixmap_priv *driver_priv;
254de2362d3Smrg    int flags;
255de2362d3Smrg    unsigned front_width;
256de2362d3Smrg    uint32_t tiling = 0;
257de2362d3Smrg    unsigned aligned_width = drawable->width;
258de2362d3Smrg
2597821949aSmrg    pixmap = pScreen->GetScreenPixmap(pScreen);
2607821949aSmrg    front_width = pixmap->drawable.width;
261de2362d3Smrg
2627821949aSmrg    pixmap = depth_pixmap = NULL;
263de2362d3Smrg
264de2362d3Smrg    if (attachment == DRI2BufferFrontLeft) {
2657821949aSmrg        if (drawable->type == DRAWABLE_PIXMAP) {
2667821949aSmrg            pixmap = (PixmapPtr)drawable;
2677821949aSmrg        } else {
2687821949aSmrg            pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable);
2697821949aSmrg        }
2707821949aSmrg        pixmap->refcnt++;
2717821949aSmrg    } else if (attachment == DRI2BufferStencil && depth_pixmap) {
2727821949aSmrg        pixmap = depth_pixmap;
2737821949aSmrg        pixmap->refcnt++;
2747821949aSmrg    } else {
275de2362d3Smrg	/* tile the back buffer */
276de2362d3Smrg	switch(attachment) {
277de2362d3Smrg	case DRI2BufferDepth:
278de2362d3Smrg	    /* macro is the preferred setting, but the 2D detiling for software
279de2362d3Smrg	     * fallbacks in mesa still has issues on some configurations
280de2362d3Smrg	     */
281de2362d3Smrg	    if (info->ChipFamily >= CHIP_FAMILY_R600) {
282de2362d3Smrg		if (info->allowColorTiling2D) {
283de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
284de2362d3Smrg		} else {
285de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
286de2362d3Smrg		}
287de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_CEDAR)
288de2362d3Smrg		    flags |= RADEON_CREATE_PIXMAP_SZBUFFER;
2897821949aSmrg	    } else
290de2362d3Smrg		flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO;
291de2362d3Smrg	    if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON)
292de2362d3Smrg		flags |= RADEON_CREATE_PIXMAP_DEPTH;
293de2362d3Smrg	    break;
294de2362d3Smrg	case DRI2BufferDepthStencil:
295de2362d3Smrg	    /* macro is the preferred setting, but the 2D detiling for software
296de2362d3Smrg	     * fallbacks in mesa still has issues on some configurations
297de2362d3Smrg	     */
298de2362d3Smrg	    if (info->ChipFamily >= CHIP_FAMILY_R600) {
299de2362d3Smrg		if (info->allowColorTiling2D) {
300de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
301de2362d3Smrg		} else {
302de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
303de2362d3Smrg		}
304de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_CEDAR)
305de2362d3Smrg		    flags |= RADEON_CREATE_PIXMAP_SZBUFFER;
3067821949aSmrg	    } else
307de2362d3Smrg		flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO;
308de2362d3Smrg	    if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON)
309de2362d3Smrg		flags |= RADEON_CREATE_PIXMAP_DEPTH;
310de2362d3Smrg
311de2362d3Smrg	    break;
312de2362d3Smrg	case DRI2BufferBackLeft:
313de2362d3Smrg	case DRI2BufferBackRight:
314de2362d3Smrg	case DRI2BufferFakeFrontLeft:
315de2362d3Smrg	case DRI2BufferFakeFrontRight:
316de2362d3Smrg	    if (info->ChipFamily >= CHIP_FAMILY_R600) {
317de2362d3Smrg		if (info->allowColorTiling2D) {
318de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
319de2362d3Smrg		} else {
320de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
321de2362d3Smrg		}
322de2362d3Smrg	    } else
323de2362d3Smrg		flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
324de2362d3Smrg	    break;
325de2362d3Smrg	default:
326de2362d3Smrg	    flags = 0;
327de2362d3Smrg	}
328de2362d3Smrg
329de2362d3Smrg	if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO)
330de2362d3Smrg	    tiling |= RADEON_TILING_MICRO;
331de2362d3Smrg	if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO)
332de2362d3Smrg	    tiling |= RADEON_TILING_MACRO;
333de2362d3Smrg
334de2362d3Smrg
3357821949aSmrg	    if (aligned_width == front_width)
3367821949aSmrg		aligned_width = pScrn->virtualX;
3377821949aSmrg
3387821949aSmrg	    pixmap = (*pScreen->CreatePixmap)(pScreen,
3397821949aSmrg					      aligned_width,
3407821949aSmrg					      drawable->height,
3417821949aSmrg					      (format != 0)?format:drawable->depth,
3427821949aSmrg					      flags);
343de2362d3Smrg    }
344de2362d3Smrg
3457821949aSmrg    if (!pixmap)
3467821949aSmrg        return NULL;
3477821949aSmrg
348de2362d3Smrg    buffers = calloc(1, sizeof *buffers);
349de2362d3Smrg    if (buffers == NULL)
350de2362d3Smrg        goto error;
351de2362d3Smrg
3527821949aSmrg    if (attachment == DRI2BufferDepth) {
3537821949aSmrg        depth_pixmap = pixmap;
354de2362d3Smrg    }
3557821949aSmrg    info->exa_force_create = TRUE;
3567821949aSmrg    exaMoveInPixmap(pixmap);
3577821949aSmrg    info->exa_force_create = FALSE;
3587821949aSmrg    driver_priv = exaGetPixmapDriverPrivate(pixmap);
3597821949aSmrg    if (!driver_priv ||
3607821949aSmrg	(radeon_gem_get_kernel_name(driver_priv->bo, &buffers->name) != 0))
3617821949aSmrg        goto error;
362de2362d3Smrg
363de2362d3Smrg    privates = calloc(1, sizeof(struct dri2_buffer_priv));
364de2362d3Smrg    if (privates == NULL)
365de2362d3Smrg        goto error;
366de2362d3Smrg
367de2362d3Smrg    buffers->attachment = attachment;
3687821949aSmrg    buffers->pitch = pixmap->devKind;
3697821949aSmrg    buffers->cpp = pixmap->drawable.bitsPerPixel / 8;
370de2362d3Smrg    buffers->driverPrivate = privates;
371de2362d3Smrg    buffers->format = format;
372de2362d3Smrg    buffers->flags = 0; /* not tiled */
373de2362d3Smrg    privates->pixmap = pixmap;
374de2362d3Smrg    privates->attachment = attachment;
375de2362d3Smrg    privates->refcnt = 1;
376de2362d3Smrg
377de2362d3Smrg    return buffers;
378de2362d3Smrg
379de2362d3Smrgerror:
380de2362d3Smrg    free(buffers);
381de2362d3Smrg    if (pixmap)
382de2362d3Smrg        (*pScreen->DestroyPixmap)(pixmap);
383de2362d3Smrg    return NULL;
384de2362d3Smrg}
3857821949aSmrg#endif
386de2362d3Smrg
3877821949aSmrg#ifndef USE_DRI2_1_1_0
3887821949aSmrgstatic void
3897821949aSmrgradeon_dri2_destroy_buffers(DrawablePtr drawable,
3907821949aSmrg                            BufferPtr buffers,
3917821949aSmrg                            int count)
392de2362d3Smrg{
3937821949aSmrg    ScreenPtr pScreen = drawable->pScreen;
3947821949aSmrg    struct dri2_buffer_priv *private;
3957821949aSmrg    int i;
396de2362d3Smrg
3977821949aSmrg    for (i = 0; i < count; i++) {
3987821949aSmrg        private = buffers[i].driverPrivate;
3997821949aSmrg        (*pScreen->DestroyPixmap)(private->pixmap);
4007821949aSmrg    }
4017821949aSmrg    if (buffers) {
4027821949aSmrg        free(buffers[0].driverPrivate);
4037821949aSmrg        free(buffers);
4047821949aSmrg    }
4057821949aSmrg}
4067821949aSmrg#else
407de2362d3Smrgstatic void
4087821949aSmrgradeon_dri2_destroy_buffer(DrawablePtr drawable, BufferPtr buffers)
409de2362d3Smrg{
410de2362d3Smrg    if(buffers)
411de2362d3Smrg    {
4127821949aSmrg        ScreenPtr pScreen = drawable->pScreen;
413de2362d3Smrg        struct dri2_buffer_priv *private = buffers->driverPrivate;
414de2362d3Smrg
415de2362d3Smrg        /* Trying to free an already freed buffer is unlikely to end well */
416de2362d3Smrg        if (private->refcnt == 0) {
417de2362d3Smrg            ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
418de2362d3Smrg
419de2362d3Smrg            xf86DrvMsg(scrn->scrnIndex, X_WARNING,
420de2362d3Smrg                       "Attempted to destroy previously destroyed buffer.\
421de2362d3Smrg This is a programming error\n");
422de2362d3Smrg            return;
423de2362d3Smrg        }
424de2362d3Smrg
425de2362d3Smrg        private->refcnt--;
426de2362d3Smrg        if (private->refcnt == 0)
427de2362d3Smrg        {
4287821949aSmrg            (*pScreen->DestroyPixmap)(private->pixmap);
429de2362d3Smrg
430de2362d3Smrg            free(buffers->driverPrivate);
431de2362d3Smrg            free(buffers);
432de2362d3Smrg        }
433de2362d3Smrg    }
434de2362d3Smrg}
4357821949aSmrg#endif
436de2362d3Smrg
437de2362d3Smrgstatic void
4387821949aSmrgradeon_dri2_copy_region(DrawablePtr drawable,
4397821949aSmrg                        RegionPtr region,
4407821949aSmrg                        BufferPtr dest_buffer,
4417821949aSmrg                        BufferPtr src_buffer)
442de2362d3Smrg{
443de2362d3Smrg    struct dri2_buffer_priv *src_private = src_buffer->driverPrivate;
444de2362d3Smrg    struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate;
4457821949aSmrg    ScreenPtr pScreen = drawable->pScreen;
446de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
447de2362d3Smrg    DrawablePtr src_drawable;
448de2362d3Smrg    DrawablePtr dst_drawable;
449de2362d3Smrg    RegionPtr copy_clip;
450de2362d3Smrg    GCPtr gc;
451de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
452de2362d3Smrg    Bool vsync;
453de2362d3Smrg
454de2362d3Smrg    if (src_private->attachment == DRI2BufferFrontLeft) {
4557821949aSmrg        src_drawable = drawable;
4567821949aSmrg    } else {
4577821949aSmrg        src_drawable = &src_private->pixmap->drawable;
458de2362d3Smrg    }
459de2362d3Smrg    if (dst_private->attachment == DRI2BufferFrontLeft) {
4607821949aSmrg        dst_drawable = drawable;
4617821949aSmrg    } else {
4627821949aSmrg        dst_drawable = &dst_private->pixmap->drawable;
463de2362d3Smrg    }
464de2362d3Smrg    gc = GetScratchGC(dst_drawable->depth, pScreen);
465de2362d3Smrg    copy_clip = REGION_CREATE(pScreen, NULL, 0);
466de2362d3Smrg    REGION_COPY(pScreen, copy_clip, region);
467de2362d3Smrg    (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0);
468de2362d3Smrg    ValidateGC(dst_drawable, gc);
469de2362d3Smrg
470de2362d3Smrg    /* If this is a full buffer swap or frontbuffer flush, throttle on the
471de2362d3Smrg     * previous one
472de2362d3Smrg     */
473de2362d3Smrg    if (dst_private->attachment == DRI2BufferFrontLeft) {
474de2362d3Smrg	if (REGION_NUM_RECTS(region) == 1) {
475de2362d3Smrg	    BoxPtr extents = REGION_EXTENTS(pScreen, region);
476de2362d3Smrg
477de2362d3Smrg	    if (extents->x1 == 0 && extents->y1 == 0 &&
478de2362d3Smrg		extents->x2 == drawable->width &&
479de2362d3Smrg		extents->y2 == drawable->height) {
4807821949aSmrg		struct radeon_exa_pixmap_priv *exa_priv =
4817821949aSmrg		    exaGetPixmapDriverPrivate(dst_private->pixmap);
482de2362d3Smrg
4837821949aSmrg		if (exa_priv && exa_priv->bo)
4847821949aSmrg		    radeon_bo_wait(exa_priv->bo);
485de2362d3Smrg	    }
486de2362d3Smrg	}
487de2362d3Smrg    }
488de2362d3Smrg
489de2362d3Smrg    vsync = info->accel_state->vsync;
490de2362d3Smrg
491de2362d3Smrg    /* Driver option "SwapbuffersWait" defines if we vsync DRI2 copy-swaps. */
492de2362d3Smrg    info->accel_state->vsync = info->swapBuffersWait;
493de2362d3Smrg
494de2362d3Smrg    (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc,
4957821949aSmrg                         0, 0, drawable->width, drawable->height, 0, 0);
496de2362d3Smrg
497de2362d3Smrg    info->accel_state->vsync = vsync;
498de2362d3Smrg
499de2362d3Smrg    FreeScratchGC(gc);
500de2362d3Smrg}
501de2362d3Smrg
5027821949aSmrg
5037821949aSmrg#ifdef USE_DRI2_SCHEDULING
504de2362d3Smrg
505de2362d3Smrgenum DRI2FrameEventType {
506de2362d3Smrg    DRI2_SWAP,
507de2362d3Smrg    DRI2_FLIP,
508de2362d3Smrg    DRI2_WAITMSC,
509de2362d3Smrg};
510de2362d3Smrg
511de2362d3Smrgtypedef struct _DRI2FrameEvent {
512de2362d3Smrg    XID drawable_id;
513de2362d3Smrg    ClientPtr client;
514de2362d3Smrg    enum DRI2FrameEventType type;
5157821949aSmrg    int frame;
516de2362d3Smrg
517de2362d3Smrg    /* for swaps & flips only */
518de2362d3Smrg    DRI2SwapEventPtr event_complete;
519de2362d3Smrg    void *event_data;
520de2362d3Smrg    DRI2BufferPtr front;
521de2362d3Smrg    DRI2BufferPtr back;
5227821949aSmrg
5237821949aSmrg    Bool valid;
5247821949aSmrg
5257821949aSmrg    struct xorg_list link;
526de2362d3Smrg} DRI2FrameEventRec, *DRI2FrameEventPtr;
527de2362d3Smrg
5287821949aSmrgtypedef struct _DRI2ClientEvents {
5297821949aSmrg    struct xorg_list   reference_list;
5307821949aSmrg} DRI2ClientEventsRec, *DRI2ClientEventsPtr;
5317821949aSmrg
5327821949aSmrg#if HAS_DEVPRIVATEKEYREC
5337821949aSmrg
5347821949aSmrgstatic DevPrivateKeyRec DRI2ClientEventsPrivateKeyRec;
5357821949aSmrg#define DRI2ClientEventsPrivateKey (&DRI2ClientEventsPrivateKeyRec)
5367821949aSmrg
5377821949aSmrg#else
5387821949aSmrg
5397821949aSmrgstatic int DRI2ClientEventsPrivateKeyIndex;
5407821949aSmrgDevPrivateKey DRI2ClientEventsPrivateKey = &DRI2ClientEventsPrivateKeyIndex;
5417821949aSmrg
5427821949aSmrg#endif /* HAS_DEVPRIVATEKEYREC */
5437821949aSmrg
5447821949aSmrg#define GetDRI2ClientEvents(pClient)	((DRI2ClientEventsPtr) \
5457821949aSmrg    dixLookupPrivate(&(pClient)->devPrivates, DRI2ClientEventsPrivateKey))
5467821949aSmrg
5477821949aSmrgstatic int
5487821949aSmrgListAddDRI2ClientEvents(ClientPtr client, struct xorg_list *entry)
5497821949aSmrg{
5507821949aSmrg    DRI2ClientEventsPtr pClientPriv;
5517821949aSmrg    pClientPriv = GetDRI2ClientEvents(client);
5527821949aSmrg
5537821949aSmrg    if (!pClientPriv) {
5547821949aSmrg        return BadAlloc;
5557821949aSmrg    }
5567821949aSmrg
5577821949aSmrg    xorg_list_add(entry, &pClientPriv->reference_list);
5587821949aSmrg    return 0;
5597821949aSmrg}
5607821949aSmrg
5617821949aSmrgstatic void
5627821949aSmrgListDelDRI2ClientEvents(ClientPtr client, struct xorg_list *entry)
5637821949aSmrg{
5647821949aSmrg    DRI2ClientEventsPtr pClientPriv;
5657821949aSmrg    pClientPriv = GetDRI2ClientEvents(client);
5667821949aSmrg
5677821949aSmrg    if (!pClientPriv) {
5687821949aSmrg        return;
5697821949aSmrg    }
5707821949aSmrg    xorg_list_del(entry);
5717821949aSmrg}
572de2362d3Smrg
573de2362d3Smrgstatic void
574de2362d3Smrgradeon_dri2_ref_buffer(BufferPtr buffer)
575de2362d3Smrg{
576de2362d3Smrg    struct dri2_buffer_priv *private = buffer->driverPrivate;
577de2362d3Smrg    private->refcnt++;
578de2362d3Smrg}
579de2362d3Smrg
580de2362d3Smrgstatic void
581de2362d3Smrgradeon_dri2_unref_buffer(BufferPtr buffer)
582de2362d3Smrg{
583de2362d3Smrg    if (buffer) {
584de2362d3Smrg        struct dri2_buffer_priv *private = buffer->driverPrivate;
585de2362d3Smrg        radeon_dri2_destroy_buffer(&(private->pixmap->drawable), buffer);
586de2362d3Smrg    }
587de2362d3Smrg}
588de2362d3Smrg
589de2362d3Smrgstatic void
590de2362d3Smrgradeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata)
591de2362d3Smrg{
5927821949aSmrg    DRI2ClientEventsPtr pClientEventsPriv;
5937821949aSmrg    DRI2FrameEventPtr ref;
594de2362d3Smrg    NewClientInfoRec *clientinfo = calldata;
595de2362d3Smrg    ClientPtr pClient = clientinfo->client;
5967821949aSmrg    pClientEventsPriv = GetDRI2ClientEvents(pClient);
597de2362d3Smrg
598de2362d3Smrg    switch (pClient->clientState) {
5997821949aSmrg    case ClientStateInitial:
6007821949aSmrg        xorg_list_init(&pClientEventsPriv->reference_list);
6017821949aSmrg        break;
6027821949aSmrg    case ClientStateRunning:
6037821949aSmrg        break;
6047821949aSmrg
605de2362d3Smrg    case ClientStateRetained:
606de2362d3Smrg    case ClientStateGone:
6077821949aSmrg        if (pClientEventsPriv) {
6087821949aSmrg            xorg_list_for_each_entry(ref, &pClientEventsPriv->reference_list, link) {
6097821949aSmrg                ref->valid = FALSE;
6107821949aSmrg                radeon_dri2_unref_buffer(ref->front);
6117821949aSmrg                radeon_dri2_unref_buffer(ref->back);
6127821949aSmrg            }
6137821949aSmrg        }
614de2362d3Smrg        break;
615de2362d3Smrg    default:
616de2362d3Smrg        break;
617de2362d3Smrg    }
618de2362d3Smrg}
619de2362d3Smrg
6207821949aSmrgstatic int radeon_dri2_drawable_crtc(DrawablePtr pDraw)
621de2362d3Smrg{
622de2362d3Smrg    ScreenPtr pScreen = pDraw->pScreen;
623de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
6247821949aSmrg    xf86CrtcPtr crtc;
6257821949aSmrg    int crtc_id = -1;
6260d16fef4Smrg
6277821949aSmrg    crtc = radeon_pick_best_crtc(pScrn,
6287821949aSmrg				 pDraw->x,
6297821949aSmrg				 pDraw->x + pDraw->width,
6307821949aSmrg				 pDraw->y,
6317821949aSmrg				 pDraw->y + pDraw->height);
6320d16fef4Smrg
6337821949aSmrg    /* Make sure the CRTC is valid and this is the real front buffer */
6347821949aSmrg    if (crtc != NULL && !crtc->rotatedData) {
6357821949aSmrg        crtc_id = drmmode_get_crtc_id(crtc);
6360d16fef4Smrg    }
6377821949aSmrg    return crtc_id;
638de2362d3Smrg}
639de2362d3Smrg
640de2362d3Smrgstatic Bool
6417821949aSmrgradeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
642de2362d3Smrg			  DrawablePtr draw, DRI2BufferPtr front,
643de2362d3Smrg			  DRI2BufferPtr back, DRI2SwapEventPtr func,
644de2362d3Smrg			  void *data, unsigned int target_msc)
645de2362d3Smrg{
646de2362d3Smrg    struct dri2_buffer_priv *back_priv;
6477821949aSmrg    struct radeon_exa_pixmap_priv *exa_priv;
648de2362d3Smrg    DRI2FrameEventPtr flip_info;
6497821949aSmrg
6507821949aSmrg    /* Main crtc for this drawable shall finally deliver pageflip event. */
6517821949aSmrg    int ref_crtc_hw_id = radeon_dri2_drawable_crtc(draw);
652de2362d3Smrg
653de2362d3Smrg    flip_info = calloc(1, sizeof(DRI2FrameEventRec));
654de2362d3Smrg    if (!flip_info)
655de2362d3Smrg	return FALSE;
656de2362d3Smrg
657de2362d3Smrg    flip_info->drawable_id = draw->id;
658de2362d3Smrg    flip_info->client = client;
659de2362d3Smrg    flip_info->type = DRI2_SWAP;
660de2362d3Smrg    flip_info->event_complete = func;
661de2362d3Smrg    flip_info->event_data = data;
662de2362d3Smrg    flip_info->frame = target_msc;
663de2362d3Smrg
664de2362d3Smrg    xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
665de2362d3Smrg		   "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info);
666de2362d3Smrg
667de2362d3Smrg    /* Page flip the full screen buffer */
668de2362d3Smrg    back_priv = back->driverPrivate;
6697821949aSmrg    exa_priv = exaGetPixmapDriverPrivate(back_priv->pixmap);
6700d16fef4Smrg
6717821949aSmrg    return radeon_do_pageflip(scrn, exa_priv->bo, flip_info, ref_crtc_hw_id);
672de2362d3Smrg}
673de2362d3Smrg
674de2362d3Smrgstatic Bool
675de2362d3Smrgupdate_front(DrawablePtr draw, DRI2BufferPtr front)
676de2362d3Smrg{
6777821949aSmrg    int r;
678de2362d3Smrg    PixmapPtr pixmap;
679de2362d3Smrg    struct dri2_buffer_priv *priv = front->driverPrivate;
6807821949aSmrg    struct radeon_exa_pixmap_priv *driver_priv;
6817821949aSmrg
6827821949aSmrg    if (draw->type == DRAWABLE_PIXMAP)
6837821949aSmrg	pixmap = (PixmapPtr)draw;
6847821949aSmrg    else
6857821949aSmrg	pixmap = (*draw->pScreen->GetWindowPixmap)((WindowPtr)draw);
686de2362d3Smrg
687de2362d3Smrg    pixmap->refcnt++;
688de2362d3Smrg
6897821949aSmrg    exaMoveInPixmap(pixmap);
6907821949aSmrg    driver_priv = exaGetPixmapDriverPrivate(pixmap);
6917821949aSmrg    r = radeon_gem_get_kernel_name(driver_priv->bo, &front->name);
6927821949aSmrg    if (r) {
693de2362d3Smrg	(*draw->pScreen->DestroyPixmap)(pixmap);
694de2362d3Smrg	return FALSE;
695de2362d3Smrg    }
696de2362d3Smrg    (*draw->pScreen->DestroyPixmap)(priv->pixmap);
697de2362d3Smrg    front->pitch = pixmap->devKind;
698de2362d3Smrg    front->cpp = pixmap->drawable.bitsPerPixel / 8;
699de2362d3Smrg    priv->pixmap = pixmap;
700de2362d3Smrg
701de2362d3Smrg    return TRUE;
702de2362d3Smrg}
703de2362d3Smrg
704de2362d3Smrgstatic Bool
705de2362d3Smrgcan_exchange(ScrnInfoPtr pScrn, DrawablePtr draw,
706de2362d3Smrg	     DRI2BufferPtr front, DRI2BufferPtr back)
707de2362d3Smrg{
708de2362d3Smrg    struct dri2_buffer_priv *front_priv = front->driverPrivate;
709de2362d3Smrg    struct dri2_buffer_priv *back_priv = back->driverPrivate;
710de2362d3Smrg    PixmapPtr front_pixmap;
711de2362d3Smrg    PixmapPtr back_pixmap = back_priv->pixmap;
712de2362d3Smrg    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
713de2362d3Smrg    int i;
714de2362d3Smrg
715de2362d3Smrg    for (i = 0; i < xf86_config->num_crtc; i++) {
716de2362d3Smrg	xf86CrtcPtr crtc = xf86_config->crtc[i];
7177821949aSmrg	if (crtc->enabled && crtc->rotatedData)
718de2362d3Smrg	    return FALSE;
719de2362d3Smrg    }
720de2362d3Smrg
721de2362d3Smrg    if (!update_front(draw, front))
722de2362d3Smrg	return FALSE;
723de2362d3Smrg
724de2362d3Smrg    front_pixmap = front_priv->pixmap;
725de2362d3Smrg
726de2362d3Smrg    if (front_pixmap->drawable.width != back_pixmap->drawable.width)
727de2362d3Smrg	return FALSE;
728de2362d3Smrg
729de2362d3Smrg    if (front_pixmap->drawable.height != back_pixmap->drawable.height)
730de2362d3Smrg	return FALSE;
731de2362d3Smrg
732de2362d3Smrg    if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel)
733de2362d3Smrg	return FALSE;
734de2362d3Smrg
735de2362d3Smrg    if (front_pixmap->devKind != back_pixmap->devKind)
736de2362d3Smrg	return FALSE;
737de2362d3Smrg
738de2362d3Smrg    return TRUE;
739de2362d3Smrg}
740de2362d3Smrg
741de2362d3Smrgstatic Bool
742de2362d3Smrgcan_flip(ScrnInfoPtr pScrn, DrawablePtr draw,
743de2362d3Smrg	 DRI2BufferPtr front, DRI2BufferPtr back)
744de2362d3Smrg{
745de2362d3Smrg    return draw->type == DRAWABLE_WINDOW &&
7467821949aSmrg	   RADEONPTR(pScrn)->allowPageFlip &&
747de2362d3Smrg	   pScrn->vtSema &&
748de2362d3Smrg	   DRI2CanFlip(draw) &&
749de2362d3Smrg	   can_exchange(pScrn, draw, front, back);
750de2362d3Smrg}
751de2362d3Smrg
752de2362d3Smrgstatic void
753de2362d3Smrgradeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
754de2362d3Smrg{
755de2362d3Smrg    struct dri2_buffer_priv *front_priv = front->driverPrivate;
756de2362d3Smrg    struct dri2_buffer_priv *back_priv = back->driverPrivate;
7577821949aSmrg    struct radeon_exa_pixmap_priv *front_radeon, *back_radeon;
758de2362d3Smrg    ScreenPtr screen;
759de2362d3Smrg    RADEONInfoPtr info;
7607821949aSmrg    struct radeon_bo *bo;
761de2362d3Smrg    int tmp;
762de2362d3Smrg
763de2362d3Smrg    /* Swap BO names so DRI works */
764de2362d3Smrg    tmp = front->name;
765de2362d3Smrg    front->name = back->name;
766de2362d3Smrg    back->name = tmp;
767de2362d3Smrg
768de2362d3Smrg    /* Swap pixmap bos */
7697821949aSmrg    front_radeon = exaGetPixmapDriverPrivate(front_priv->pixmap);
7707821949aSmrg    back_radeon = exaGetPixmapDriverPrivate(back_priv->pixmap);
7717821949aSmrg    bo = back_radeon->bo;
7727821949aSmrg    back_radeon->bo = front_radeon->bo;
7737821949aSmrg    front_radeon->bo = bo;
774de2362d3Smrg
775de2362d3Smrg    /* Do we need to update the Screen? */
776de2362d3Smrg    screen = draw->pScreen;
777de2362d3Smrg    info = RADEONPTR(xf86ScreenToScrn(screen));
7787821949aSmrg    if (front_radeon->bo == info->front_bo) {
779de2362d3Smrg	radeon_bo_unref(info->front_bo);
7807821949aSmrg	info->front_bo = back_radeon->bo;
7817821949aSmrg	radeon_bo_ref(info->front_bo);
7827821949aSmrg	front_radeon = exaGetPixmapDriverPrivate(screen->GetScreenPixmap(screen));
7837821949aSmrg        front_radeon->bo = bo;
784de2362d3Smrg    }
785de2362d3Smrg}
786de2362d3Smrg
7877821949aSmrgvoid radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
7887821949aSmrg                                     unsigned int tv_usec, void *event_data)
789de2362d3Smrg{
790de2362d3Smrg    DRI2FrameEventPtr event = event_data;
791de2362d3Smrg    DrawablePtr drawable;
7927821949aSmrg    ScreenPtr screen;
7937821949aSmrg    ScrnInfoPtr scrn;
794de2362d3Smrg    int status;
795de2362d3Smrg    int swap_type;
796de2362d3Smrg    BoxRec box;
797de2362d3Smrg    RegionRec region;
798de2362d3Smrg
7997821949aSmrg    if (!event->valid)
8007821949aSmrg	goto cleanup;
8017821949aSmrg
802de2362d3Smrg    status = dixLookupDrawable(&drawable, event->drawable_id, serverClient,
803de2362d3Smrg                               M_ANY, DixWriteAccess);
804de2362d3Smrg    if (status != Success)
805de2362d3Smrg        goto cleanup;
806de2362d3Smrg
8077821949aSmrg    screen = drawable->pScreen;
8087821949aSmrg    scrn = xf86ScreenToScrn(screen);
809de2362d3Smrg
810de2362d3Smrg    switch (event->type) {
811de2362d3Smrg    case DRI2_FLIP:
812de2362d3Smrg	if (can_flip(scrn, drawable, event->front, event->back) &&
8137821949aSmrg	    radeon_dri2_schedule_flip(scrn,
814de2362d3Smrg				      event->client,
815de2362d3Smrg				      drawable,
816de2362d3Smrg				      event->front,
817de2362d3Smrg				      event->back,
818de2362d3Smrg				      event->event_complete,
819de2362d3Smrg				      event->event_data,
820de2362d3Smrg				      event->frame)) {
821de2362d3Smrg	    radeon_dri2_exchange_buffers(drawable, event->front, event->back);
822de2362d3Smrg	    break;
823de2362d3Smrg	}
824de2362d3Smrg	/* else fall through to exchange/blit */
825de2362d3Smrg    case DRI2_SWAP:
826de2362d3Smrg	if (DRI2CanExchange(drawable) &&
827de2362d3Smrg	    can_exchange(scrn, drawable, event->front, event->back)) {
828de2362d3Smrg	    radeon_dri2_exchange_buffers(drawable, event->front, event->back);
829de2362d3Smrg	    swap_type = DRI2_EXCHANGE_COMPLETE;
830de2362d3Smrg	} else {
831de2362d3Smrg	    box.x1 = 0;
832de2362d3Smrg	    box.y1 = 0;
833de2362d3Smrg	    box.x2 = drawable->width;
834de2362d3Smrg	    box.y2 = drawable->height;
835de2362d3Smrg	    REGION_INIT(pScreen, &region, &box, 0);
836de2362d3Smrg	    radeon_dri2_copy_region(drawable, &region, event->front, event->back);
837de2362d3Smrg	    swap_type = DRI2_BLIT_COMPLETE;
838de2362d3Smrg	}
839de2362d3Smrg
8407821949aSmrg        DRI2SwapComplete(event->client, drawable, frame, tv_sec, tv_usec,
8417821949aSmrg                swap_type, event->event_complete, event->event_data);
842de2362d3Smrg
843de2362d3Smrg        break;
844de2362d3Smrg    case DRI2_WAITMSC:
8457821949aSmrg        DRI2WaitMSCComplete(event->client, drawable, frame, tv_sec, tv_usec);
846de2362d3Smrg        break;
847de2362d3Smrg    default:
848de2362d3Smrg        /* Unknown type */
849de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
850de2362d3Smrg                "%s: unknown vblank event received\n", __func__);
851de2362d3Smrg        break;
852de2362d3Smrg    }
853de2362d3Smrg
854de2362d3Smrgcleanup:
8557821949aSmrg    if (event->valid) {
8567821949aSmrg        radeon_dri2_unref_buffer(event->front);
8577821949aSmrg        radeon_dri2_unref_buffer(event->back);
8587821949aSmrg        ListDelDRI2ClientEvents(event->client, &event->link);
8597821949aSmrg    }
8607821949aSmrg    free(event);
861de2362d3Smrg}
862de2362d3Smrg
8637821949aSmrgstatic drmVBlankSeqType populate_vbl_request_type(RADEONInfoPtr info, int crtc)
864de2362d3Smrg{
865de2362d3Smrg    drmVBlankSeqType type = 0;
866de2362d3Smrg
8677821949aSmrg    if (crtc == 1)
868de2362d3Smrg        type |= DRM_VBLANK_SECONDARY;
8697821949aSmrg    else if (crtc > 1)
870de2362d3Smrg#ifdef DRM_VBLANK_HIGH_CRTC_SHIFT
8717821949aSmrg	type |= (crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) &
872de2362d3Smrg		DRM_VBLANK_HIGH_CRTC_MASK;
873de2362d3Smrg#else
874de2362d3Smrg	ErrorF("radeon driver bug: %s called for CRTC %d > 1, but "
875de2362d3Smrg	       "DRM_VBLANK_HIGH_CRTC_MASK not defined at build time\n",
8767821949aSmrg	       __func__, crtc);
877de2362d3Smrg#endif
878de2362d3Smrg
879de2362d3Smrg    return type;
880de2362d3Smrg}
881de2362d3Smrg
882de2362d3Smrg/*
8837821949aSmrg * Get current frame count and frame count timestamp, based on drawable's
8847821949aSmrg * crtc.
885de2362d3Smrg */
886de2362d3Smrgstatic int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
887de2362d3Smrg{
8887821949aSmrg    ScreenPtr screen = draw->pScreen;
8897821949aSmrg    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
8907821949aSmrg    RADEONInfoPtr info = RADEONPTR(scrn);
8917821949aSmrg    drmVBlank vbl;
8927821949aSmrg    int ret;
8937821949aSmrg    int crtc = radeon_dri2_drawable_crtc(draw);
894de2362d3Smrg
895de2362d3Smrg    /* Drawable not displayed, make up a value */
8967821949aSmrg    if (crtc == -1) {
897de2362d3Smrg        *ust = 0;
898de2362d3Smrg        *msc = 0;
899de2362d3Smrg        return TRUE;
900de2362d3Smrg    }
9017821949aSmrg    vbl.request.type = DRM_VBLANK_RELATIVE;
9027821949aSmrg    vbl.request.type |= populate_vbl_request_type(info, crtc);
9037821949aSmrg    vbl.request.sequence = 0;
904de2362d3Smrg
9057821949aSmrg    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
906de2362d3Smrg    if (ret) {
9077821949aSmrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
9087821949aSmrg                "get vblank counter failed: %s\n", strerror(errno));
9097821949aSmrg        return FALSE;
910de2362d3Smrg    }
911de2362d3Smrg
9127821949aSmrg    *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec;
9137821949aSmrg    *msc = vbl.reply.sequence;
9147821949aSmrg
9157821949aSmrg    return TRUE;
916de2362d3Smrg}
917de2362d3Smrg
918de2362d3Smrg/*
919de2362d3Smrg * Request a DRM event when the requested conditions will be satisfied.
920de2362d3Smrg *
921de2362d3Smrg * We need to handle the event and ask the server to wake up the client when
922de2362d3Smrg * we receive it.
923de2362d3Smrg */
924de2362d3Smrgstatic int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw,
925de2362d3Smrg                                         CARD64 target_msc, CARD64 divisor,
926de2362d3Smrg                                         CARD64 remainder)
927de2362d3Smrg{
928de2362d3Smrg    ScreenPtr screen = draw->pScreen;
929de2362d3Smrg    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
930de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(scrn);
931de2362d3Smrg    DRI2FrameEventPtr wait_info = NULL;
932de2362d3Smrg    drmVBlank vbl;
9337821949aSmrg    int ret, crtc = radeon_dri2_drawable_crtc(draw);
934de2362d3Smrg    CARD64 current_msc;
935de2362d3Smrg
936de2362d3Smrg    /* Truncate to match kernel interfaces; means occasional overflow
937de2362d3Smrg     * misses, but that's generally not a big deal */
938de2362d3Smrg    target_msc &= 0xffffffff;
939de2362d3Smrg    divisor &= 0xffffffff;
940de2362d3Smrg    remainder &= 0xffffffff;
941de2362d3Smrg
942de2362d3Smrg    /* Drawable not visible, return immediately */
9437821949aSmrg    if (crtc == -1)
944de2362d3Smrg        goto out_complete;
945de2362d3Smrg
946de2362d3Smrg    wait_info = calloc(1, sizeof(DRI2FrameEventRec));
947de2362d3Smrg    if (!wait_info)
948de2362d3Smrg        goto out_complete;
949de2362d3Smrg
950de2362d3Smrg    wait_info->drawable_id = draw->id;
951de2362d3Smrg    wait_info->client = client;
952de2362d3Smrg    wait_info->type = DRI2_WAITMSC;
9537821949aSmrg    wait_info->valid = TRUE;
954de2362d3Smrg
9557821949aSmrg    if (ListAddDRI2ClientEvents(client, &wait_info->link)) {
9567821949aSmrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
9577821949aSmrg                "add events to client private failed.\n");
9587821949aSmrg        free(wait_info);
9597821949aSmrg        wait_info = NULL;
9607821949aSmrg        goto out_complete;
961de2362d3Smrg    }
962de2362d3Smrg
963de2362d3Smrg    /* Get current count */
964de2362d3Smrg    vbl.request.type = DRM_VBLANK_RELATIVE;
9657821949aSmrg    vbl.request.type |= populate_vbl_request_type(info, crtc);
966de2362d3Smrg    vbl.request.sequence = 0;
967de2362d3Smrg    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
968de2362d3Smrg    if (ret) {
969de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
970de2362d3Smrg                "get vblank counter failed: %s\n", strerror(errno));
971de2362d3Smrg        goto out_complete;
972de2362d3Smrg    }
973de2362d3Smrg
9747821949aSmrg    current_msc = vbl.reply.sequence;
9750d16fef4Smrg
976de2362d3Smrg    /*
977de2362d3Smrg     * If divisor is zero, or current_msc is smaller than target_msc,
978de2362d3Smrg     * we just need to make sure target_msc passes  before waking up the
979de2362d3Smrg     * client.
980de2362d3Smrg     */
981de2362d3Smrg    if (divisor == 0 || current_msc < target_msc) {
982de2362d3Smrg        /* If target_msc already reached or passed, set it to
983de2362d3Smrg         * current_msc to ensure we return a reasonable value back
984de2362d3Smrg         * to the caller. This keeps the client from continually
985de2362d3Smrg         * sending us MSC targets from the past by forcibly updating
986de2362d3Smrg         * their count on this call.
987de2362d3Smrg         */
988de2362d3Smrg        if (current_msc >= target_msc)
989de2362d3Smrg            target_msc = current_msc;
990de2362d3Smrg        vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
9917821949aSmrg	vbl.request.type |= populate_vbl_request_type(info, crtc);
9927821949aSmrg        vbl.request.sequence = target_msc;
9937821949aSmrg        vbl.request.signal = (unsigned long)wait_info;
994de2362d3Smrg        ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
995de2362d3Smrg        if (ret) {
996de2362d3Smrg            xf86DrvMsg(scrn->scrnIndex, X_WARNING,
997de2362d3Smrg                    "get vblank counter failed: %s\n", strerror(errno));
998de2362d3Smrg            goto out_complete;
999de2362d3Smrg        }
1000de2362d3Smrg
10017821949aSmrg        wait_info->frame = vbl.reply.sequence;
1002de2362d3Smrg        DRI2BlockClient(client, draw);
1003de2362d3Smrg        return TRUE;
1004de2362d3Smrg    }
1005de2362d3Smrg
1006de2362d3Smrg    /*
1007de2362d3Smrg     * If we get here, target_msc has already passed or we don't have one,
1008de2362d3Smrg     * so we queue an event that will satisfy the divisor/remainder equation.
1009de2362d3Smrg     */
1010de2362d3Smrg    vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
10117821949aSmrg    vbl.request.type |= populate_vbl_request_type(info, crtc);
1012de2362d3Smrg
1013de2362d3Smrg    vbl.request.sequence = current_msc - (current_msc % divisor) +
10147821949aSmrg        remainder;
1015de2362d3Smrg
1016de2362d3Smrg    /*
1017de2362d3Smrg     * If calculated remainder is larger than requested remainder,
1018de2362d3Smrg     * it means we've passed the last point where
1019de2362d3Smrg     * seq % divisor == remainder, so we need to wait for the next time
1020de2362d3Smrg     * that will happen.
1021de2362d3Smrg     */
1022de2362d3Smrg    if ((current_msc % divisor) >= remainder)
1023de2362d3Smrg        vbl.request.sequence += divisor;
1024de2362d3Smrg
10257821949aSmrg    vbl.request.signal = (unsigned long)wait_info;
1026de2362d3Smrg    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
1027de2362d3Smrg    if (ret) {
1028de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1029de2362d3Smrg                "get vblank counter failed: %s\n", strerror(errno));
1030de2362d3Smrg        goto out_complete;
1031de2362d3Smrg    }
1032de2362d3Smrg
10337821949aSmrg    wait_info->frame = vbl.reply.sequence;
1034de2362d3Smrg    DRI2BlockClient(client, draw);
1035de2362d3Smrg
1036de2362d3Smrg    return TRUE;
1037de2362d3Smrg
1038de2362d3Smrgout_complete:
10397821949aSmrg    if (wait_info) {
10407821949aSmrg        ListDelDRI2ClientEvents(wait_info->client, &wait_info->link);
10417821949aSmrg        free(wait_info);
10427821949aSmrg    }
10437821949aSmrg    DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
1044de2362d3Smrg    return TRUE;
1045de2362d3Smrg}
1046de2362d3Smrg
10477821949aSmrgvoid radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
10487821949aSmrg				    unsigned int tv_usec, void *event_data)
10497821949aSmrg{
10507821949aSmrg    DRI2FrameEventPtr flip = event_data;
10517821949aSmrg    DrawablePtr drawable;
10527821949aSmrg    ScreenPtr screen;
10537821949aSmrg    ScrnInfoPtr scrn;
10547821949aSmrg    int status;
10557821949aSmrg    PixmapPtr pixmap;
10567821949aSmrg
10577821949aSmrg    status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient,
10587821949aSmrg			       M_ANY, DixWriteAccess);
10597821949aSmrg    if (status != Success) {
10607821949aSmrg	free(flip);
10617821949aSmrg	return;
10627821949aSmrg    }
10637821949aSmrg
10647821949aSmrg    screen = drawable->pScreen;
10657821949aSmrg    scrn = xf86ScreenToScrn(screen);
10667821949aSmrg
10677821949aSmrg    pixmap = screen->GetScreenPixmap(screen);
10687821949aSmrg    xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
10697821949aSmrg		   "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n",
10707821949aSmrg		   __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4);
10717821949aSmrg
10727821949aSmrg    /* We assume our flips arrive in order, so we don't check the frame */
10737821949aSmrg    switch (flip->type) {
10747821949aSmrg    case DRI2_SWAP:
10757821949aSmrg	/* Check for too small vblank count of pageflip completion, taking wraparound
10767821949aSmrg	 * into account. This usually means some defective kms pageflip completion,
10777821949aSmrg	 * causing wrong (msc, ust) return values and possible visual corruption.
10787821949aSmrg	 */
10797821949aSmrg	if ((frame < flip->frame) && (flip->frame - frame < 5)) {
10807821949aSmrg	    xf86DrvMsg(scrn->scrnIndex, X_WARNING,
10817821949aSmrg		       "%s: Pageflip completion event has impossible msc %d < target_msc %d\n",
10827821949aSmrg		        __func__, frame, flip->frame);
10837821949aSmrg	    /* All-Zero values signal failure of (msc, ust) timestamping to client. */
10847821949aSmrg	    frame = tv_sec = tv_usec = 0;
10857821949aSmrg	}
10867821949aSmrg
10877821949aSmrg	DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
10887821949aSmrg			 DRI2_FLIP_COMPLETE, flip->event_complete,
10897821949aSmrg			 flip->event_data);
10907821949aSmrg	break;
10917821949aSmrg    default:
10927821949aSmrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__);
10937821949aSmrg	/* Unknown type */
10947821949aSmrg	break;
10957821949aSmrg    }
10967821949aSmrg
10977821949aSmrg    free(flip);
10987821949aSmrg}
10997821949aSmrg
1100de2362d3Smrg/*
1101de2362d3Smrg * ScheduleSwap is responsible for requesting a DRM vblank event for the
1102de2362d3Smrg * appropriate frame.
1103de2362d3Smrg *
1104de2362d3Smrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
1105de2362d3Smrg * the vblank requested can simply be the last queued swap frame + the swap
1106de2362d3Smrg * interval for the drawable.
1107de2362d3Smrg *
1108de2362d3Smrg * In the case of a page flip, we request an event for the last queued swap
1109de2362d3Smrg * frame + swap interval - 1, since we'll need to queue the flip for the frame
1110de2362d3Smrg * immediately following the received event.
1111de2362d3Smrg *
1112de2362d3Smrg * The client will be blocked if it tries to perform further GL commands
1113de2362d3Smrg * after queueing a swap, though in the Intel case after queueing a flip, the
1114de2362d3Smrg * client is free to queue more commands; they'll block in the kernel if
1115de2362d3Smrg * they access buffers busy with the flip.
1116de2362d3Smrg *
1117de2362d3Smrg * When the swap is complete, the driver should call into the server so it
1118de2362d3Smrg * can send any swap complete events that have been requested.
1119de2362d3Smrg */
1120de2362d3Smrgstatic int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
1121de2362d3Smrg                                     DRI2BufferPtr front, DRI2BufferPtr back,
1122de2362d3Smrg                                     CARD64 *target_msc, CARD64 divisor,
1123de2362d3Smrg                                     CARD64 remainder, DRI2SwapEventPtr func,
1124de2362d3Smrg                                     void *data)
1125de2362d3Smrg{
1126de2362d3Smrg    ScreenPtr screen = draw->pScreen;
1127de2362d3Smrg    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1128de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(scrn);
1129de2362d3Smrg    drmVBlank vbl;
11307821949aSmrg    int ret, crtc= radeon_dri2_drawable_crtc(draw), flip = 0;
1131de2362d3Smrg    DRI2FrameEventPtr swap_info = NULL;
11327821949aSmrg    enum DRI2FrameEventType swap_type = DRI2_SWAP;
1133de2362d3Smrg    CARD64 current_msc;
1134de2362d3Smrg    BoxRec box;
1135de2362d3Smrg    RegionRec region;
1136de2362d3Smrg
1137de2362d3Smrg    /* Truncate to match kernel interfaces; means occasional overflow
1138de2362d3Smrg     * misses, but that's generally not a big deal */
1139de2362d3Smrg    *target_msc &= 0xffffffff;
1140de2362d3Smrg    divisor &= 0xffffffff;
1141de2362d3Smrg    remainder &= 0xffffffff;
1142de2362d3Smrg
1143de2362d3Smrg    /* radeon_dri2_frame_event_handler will get called some unknown time in the
1144de2362d3Smrg     * future with these buffers.  Take a reference to ensure that they won't
1145de2362d3Smrg     * get destroyed before then.
1146de2362d3Smrg     */
1147de2362d3Smrg    radeon_dri2_ref_buffer(front);
1148de2362d3Smrg    radeon_dri2_ref_buffer(back);
1149de2362d3Smrg
11507821949aSmrg    /* Drawable not displayed... just complete the swap */
11517821949aSmrg    if (crtc == -1)
1152de2362d3Smrg        goto blit_fallback;
1153de2362d3Smrg
1154de2362d3Smrg    swap_info = calloc(1, sizeof(DRI2FrameEventRec));
1155de2362d3Smrg    if (!swap_info)
1156de2362d3Smrg        goto blit_fallback;
1157de2362d3Smrg
1158de2362d3Smrg    swap_info->drawable_id = draw->id;
1159de2362d3Smrg    swap_info->client = client;
1160de2362d3Smrg    swap_info->event_complete = func;
1161de2362d3Smrg    swap_info->event_data = data;
1162de2362d3Smrg    swap_info->front = front;
1163de2362d3Smrg    swap_info->back = back;
11647821949aSmrg    swap_info->valid = TRUE;
11657821949aSmrg    if (ListAddDRI2ClientEvents(client, &swap_info->link)) {
1166de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
11677821949aSmrg                "add events to client private failed.\n");
11687821949aSmrg        free(swap_info);
11697821949aSmrg        swap_info = NULL;
1170de2362d3Smrg        goto blit_fallback;
1171de2362d3Smrg    }
1172de2362d3Smrg
1173de2362d3Smrg    /* Get current count */
1174de2362d3Smrg    vbl.request.type = DRM_VBLANK_RELATIVE;
11757821949aSmrg    vbl.request.type |= populate_vbl_request_type(info, crtc);
1176de2362d3Smrg    vbl.request.sequence = 0;
1177de2362d3Smrg    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
1178de2362d3Smrg    if (ret) {
1179de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1180de2362d3Smrg                "first get vblank counter failed: %s\n",
1181de2362d3Smrg                strerror(errno));
11827821949aSmrg        goto blit_fallback;
1183de2362d3Smrg    }
1184de2362d3Smrg
11857821949aSmrg    current_msc = vbl.reply.sequence;
1186de2362d3Smrg
1187de2362d3Smrg    /* Flips need to be submitted one frame before */
1188de2362d3Smrg    if (can_flip(scrn, draw, front, back)) {
11897821949aSmrg	swap_type = DRI2_FLIP;
1190de2362d3Smrg	flip = 1;
1191de2362d3Smrg    }
1192de2362d3Smrg
11937821949aSmrg    swap_info->type = swap_type;
11947821949aSmrg
11957821949aSmrg    /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
1196de2362d3Smrg     * Do it early, so handling of different timing constraints
1197de2362d3Smrg     * for divisor, remainder and msc vs. target_msc works.
1198de2362d3Smrg     */
1199de2362d3Smrg    if (*target_msc > 0)
1200de2362d3Smrg        *target_msc -= flip;
1201de2362d3Smrg
1202de2362d3Smrg    /*
1203de2362d3Smrg     * If divisor is zero, or current_msc is smaller than target_msc
1204de2362d3Smrg     * we just need to make sure target_msc passes before initiating
1205de2362d3Smrg     * the swap.
1206de2362d3Smrg     */
1207de2362d3Smrg    if (divisor == 0 || current_msc < *target_msc) {
1208de2362d3Smrg        vbl.request.type =  DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
1209de2362d3Smrg        /* If non-pageflipping, but blitting/exchanging, we need to use
1210de2362d3Smrg         * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
1211de2362d3Smrg         * on.
1212de2362d3Smrg         */
1213de2362d3Smrg        if (flip == 0)
1214de2362d3Smrg            vbl.request.type |= DRM_VBLANK_NEXTONMISS;
12157821949aSmrg	vbl.request.type |= populate_vbl_request_type(info, crtc);
1216de2362d3Smrg
1217de2362d3Smrg        /* If target_msc already reached or passed, set it to
1218de2362d3Smrg         * current_msc to ensure we return a reasonable value back
1219de2362d3Smrg         * to the caller. This makes swap_interval logic more robust.
1220de2362d3Smrg         */
1221de2362d3Smrg        if (current_msc >= *target_msc)
1222de2362d3Smrg            *target_msc = current_msc;
1223de2362d3Smrg
12247821949aSmrg        vbl.request.sequence = *target_msc;
12257821949aSmrg        vbl.request.signal = (unsigned long)swap_info;
1226de2362d3Smrg        ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
1227de2362d3Smrg        if (ret) {
1228de2362d3Smrg            xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1229de2362d3Smrg                    "divisor 0 get vblank counter failed: %s\n",
1230de2362d3Smrg                    strerror(errno));
12317821949aSmrg            goto blit_fallback;
1232de2362d3Smrg        }
1233de2362d3Smrg
12347821949aSmrg        *target_msc = vbl.reply.sequence + flip;
1235de2362d3Smrg        swap_info->frame = *target_msc;
1236de2362d3Smrg
1237de2362d3Smrg        return TRUE;
1238de2362d3Smrg    }
1239de2362d3Smrg
1240de2362d3Smrg    /*
1241de2362d3Smrg     * If we get here, target_msc has already passed or we don't have one,
1242de2362d3Smrg     * and we need to queue an event that will satisfy the divisor/remainder
1243de2362d3Smrg     * equation.
1244de2362d3Smrg     */
1245de2362d3Smrg    vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
1246de2362d3Smrg    if (flip == 0)
1247de2362d3Smrg        vbl.request.type |= DRM_VBLANK_NEXTONMISS;
12487821949aSmrg    vbl.request.type |= populate_vbl_request_type(info, crtc);
1249de2362d3Smrg
1250de2362d3Smrg    vbl.request.sequence = current_msc - (current_msc % divisor) +
12517821949aSmrg        remainder;
1252de2362d3Smrg
1253de2362d3Smrg    /*
1254de2362d3Smrg     * If the calculated deadline vbl.request.sequence is smaller than
1255de2362d3Smrg     * or equal to current_msc, it means we've passed the last point
1256de2362d3Smrg     * when effective onset frame seq could satisfy
1257de2362d3Smrg     * seq % divisor == remainder, so we need to wait for the next time
1258de2362d3Smrg     * this will happen.
1259de2362d3Smrg
1260de2362d3Smrg     * This comparison takes the 1 frame swap delay in pageflipping mode
1261de2362d3Smrg     * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
1262de2362d3Smrg     * if we are blitting/exchanging instead of flipping.
1263de2362d3Smrg     */
1264de2362d3Smrg    if (vbl.request.sequence <= current_msc)
1265de2362d3Smrg        vbl.request.sequence += divisor;
1266de2362d3Smrg
1267de2362d3Smrg    /* Account for 1 frame extra pageflip delay if flip > 0 */
1268de2362d3Smrg    vbl.request.sequence -= flip;
1269de2362d3Smrg
12707821949aSmrg    vbl.request.signal = (unsigned long)swap_info;
1271de2362d3Smrg    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
1272de2362d3Smrg    if (ret) {
1273de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1274de2362d3Smrg                "final get vblank counter failed: %s\n",
1275de2362d3Smrg                strerror(errno));
12767821949aSmrg        goto blit_fallback;
1277de2362d3Smrg    }
1278de2362d3Smrg
1279de2362d3Smrg    /* Adjust returned value for 1 fame pageflip offset of flip > 0 */
12807821949aSmrg    *target_msc = vbl.reply.sequence + flip;
1281de2362d3Smrg    swap_info->frame = *target_msc;
1282de2362d3Smrg
1283de2362d3Smrg    return TRUE;
1284de2362d3Smrg
1285de2362d3Smrgblit_fallback:
12867821949aSmrg    box.x1 = 0;
12877821949aSmrg    box.y1 = 0;
12887821949aSmrg    box.x2 = draw->width;
12897821949aSmrg    box.y2 = draw->height;
12907821949aSmrg    REGION_INIT(pScreen, &region, &box, 0);
1291de2362d3Smrg
12927821949aSmrg    radeon_dri2_copy_region(draw, &region, front, back);
1293de2362d3Smrg
12947821949aSmrg    DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
12957821949aSmrg    if (swap_info) {
12967821949aSmrg        ListDelDRI2ClientEvents(swap_info->client, &swap_info->link);
12977821949aSmrg        free(swap_info);
12980d16fef4Smrg    }
1299de2362d3Smrg
13007821949aSmrg    radeon_dri2_unref_buffer(front);
13017821949aSmrg    radeon_dri2_unref_buffer(back);
13027821949aSmrg
1303de2362d3Smrg    *target_msc = 0; /* offscreen, so zero out target vblank count */
1304de2362d3Smrg    return TRUE;
1305de2362d3Smrg}
1306de2362d3Smrg
13077821949aSmrg#endif /* USE_DRI2_SCHEDULING */
13087821949aSmrg
1309de2362d3Smrg
1310de2362d3SmrgBool
1311de2362d3Smrgradeon_dri2_screen_init(ScreenPtr pScreen)
1312de2362d3Smrg{
1313de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1314de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1315de2362d3Smrg    DRI2InfoRec dri2_info = { 0 };
13167821949aSmrg#ifdef USE_DRI2_SCHEDULING
13177821949aSmrg    RADEONEntPtr pRADEONEnt   = RADEONEntPriv(pScrn);
1318de2362d3Smrg    const char *driverNames[2];
1319de2362d3Smrg    Bool scheduling_works = TRUE;
13207821949aSmrg#endif
1321de2362d3Smrg
13227821949aSmrg    if (!info->useEXA) {
13237821949aSmrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 requires EXA\n");
1324de2362d3Smrg        return FALSE;
13257821949aSmrg    }
1326de2362d3Smrg
1327de2362d3Smrg    info->dri2.device_name = drmGetDeviceNameFromFd(info->dri2.drm_fd);
1328de2362d3Smrg
13297821949aSmrg    if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) {
1330de2362d3Smrg        dri2_info.driverName = R600_DRIVER_NAME;
1331de2362d3Smrg    } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) {
1332de2362d3Smrg        dri2_info.driverName = R300_DRIVER_NAME;
1333de2362d3Smrg    } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) {
1334de2362d3Smrg        dri2_info.driverName = R200_DRIVER_NAME;
1335de2362d3Smrg    } else {
1336de2362d3Smrg        dri2_info.driverName = RADEON_DRIVER_NAME;
1337de2362d3Smrg    }
1338de2362d3Smrg    dri2_info.fd = info->dri2.drm_fd;
1339de2362d3Smrg    dri2_info.deviceName = info->dri2.device_name;
13407821949aSmrg#ifndef USE_DRI2_1_1_0
13417821949aSmrg    dri2_info.version = 1;
13427821949aSmrg    dri2_info.CreateBuffers = radeon_dri2_create_buffers;
13437821949aSmrg    dri2_info.DestroyBuffers = radeon_dri2_destroy_buffers;
13447821949aSmrg#else
1345de2362d3Smrg    dri2_info.version = DRI2INFOREC_VERSION;
1346de2362d3Smrg    dri2_info.CreateBuffer = radeon_dri2_create_buffer;
1347de2362d3Smrg    dri2_info.DestroyBuffer = radeon_dri2_destroy_buffer;
13487821949aSmrg#endif
1349de2362d3Smrg    dri2_info.CopyRegion = radeon_dri2_copy_region;
1350de2362d3Smrg
13517821949aSmrg#ifdef USE_DRI2_SCHEDULING
13527821949aSmrg    if (info->dri->pKernelDRMVersion->version_minor < 4) {
1353de2362d3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for "
1354de2362d3Smrg		   "sync extension\n");
1355de2362d3Smrg	scheduling_works = FALSE;
1356de2362d3Smrg    }
1357de2362d3Smrg
13587821949aSmrg    if (scheduling_works && info->drmmode.mode_res->count_crtcs > 2) {
1359de2362d3Smrg#ifdef DRM_CAP_VBLANK_HIGH_CRTC
1360de2362d3Smrg	uint64_t cap_value;
1361de2362d3Smrg
1362de2362d3Smrg	if (drmGetCap(info->dri2.drm_fd, DRM_CAP_VBLANK_HIGH_CRTC, &cap_value)) {
1363de2362d3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel "
1364de2362d3Smrg		       "for VBLANKs on CRTC > 1\n");
1365de2362d3Smrg	    scheduling_works = FALSE;
1366de2362d3Smrg	} else if (!cap_value) {
1367de2362d3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Your kernel does not "
1368de2362d3Smrg		       "handle VBLANKs on CRTC > 1\n");
1369de2362d3Smrg	    scheduling_works = FALSE;
1370de2362d3Smrg	}
1371de2362d3Smrg#else
1372de2362d3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need to rebuild against a "
1373de2362d3Smrg		   "newer libdrm to handle VBLANKs on CRTC > 1\n");
1374de2362d3Smrg	scheduling_works = FALSE;
1375de2362d3Smrg#endif
1376de2362d3Smrg    }
1377de2362d3Smrg
1378de2362d3Smrg    if (scheduling_works) {
1379de2362d3Smrg        dri2_info.version = 4;
1380de2362d3Smrg        dri2_info.ScheduleSwap = radeon_dri2_schedule_swap;
1381de2362d3Smrg        dri2_info.GetMSC = radeon_dri2_get_msc;
1382de2362d3Smrg        dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc;
1383de2362d3Smrg        dri2_info.numDrivers = RADEON_ARRAY_SIZE(driverNames);
1384de2362d3Smrg        dri2_info.driverNames = driverNames;
13857821949aSmrg        driverNames[0] = driverNames[1] = dri2_info.driverName;
13867821949aSmrg
13877821949aSmrg	if (pRADEONEnt->dri2_info_cnt == 0) {
13887821949aSmrg#if HAS_DIXREGISTERPRIVATEKEY
13897821949aSmrg	    if (!dixRegisterPrivateKey(DRI2ClientEventsPrivateKey,
13907821949aSmrg				       PRIVATE_CLIENT, sizeof(DRI2ClientEventsRec))) {
13917821949aSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 registering "
13927821949aSmrg			   "private key to client failed\n");
13937821949aSmrg		return FALSE;
13947821949aSmrg	    }
13957821949aSmrg#else
13967821949aSmrg	    if (!dixRequestPrivate(DRI2ClientEventsPrivateKey,
13977821949aSmrg				   sizeof(DRI2ClientEventsRec))) {
13987821949aSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 requesting "
13997821949aSmrg			   "private key to client failed\n");
1400de2362d3Smrg		return FALSE;
1401de2362d3Smrg	    }
14027821949aSmrg#endif
1403de2362d3Smrg
1404de2362d3Smrg	    AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0);
1405de2362d3Smrg	}
1406de2362d3Smrg
14077821949aSmrg	pRADEONEnt->dri2_info_cnt++;
1408de2362d3Smrg    }
1409de2362d3Smrg#endif
1410de2362d3Smrg
1411de2362d3Smrg    info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info);
1412de2362d3Smrg    return info->dri2.enabled;
1413de2362d3Smrg}
1414de2362d3Smrg
1415de2362d3Smrgvoid radeon_dri2_close_screen(ScreenPtr pScreen)
1416de2362d3Smrg{
1417de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1418de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
14197821949aSmrg#ifdef USE_DRI2_SCHEDULING
14207821949aSmrg    RADEONEntPtr pRADEONEnt   = RADEONEntPriv(pScrn);
1421de2362d3Smrg
14227821949aSmrg    if (--pRADEONEnt->dri2_info_cnt == 0)
1423de2362d3Smrg    	DeleteCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0);
14247821949aSmrg#endif
1425de2362d3Smrg    DRI2CloseScreen(pScreen);
1426de2362d3Smrg    drmFree(info->dri2.device_name);
1427de2362d3Smrg}
1428de2362d3Smrg
14297821949aSmrg#endif
1430