radeon_dri2.c revision 0d16fef4
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 "radeon.h"
33de2362d3Smrg#include "radeon_dri2.h"
34de2362d3Smrg#include "radeon_video.h"
35de2362d3Smrg
36de2362d3Smrg#ifdef DRI2
37de2362d3Smrg
38de2362d3Smrg#include <sys/types.h>
39de2362d3Smrg#include <sys/stat.h>
40de2362d3Smrg#include <fcntl.h>
41de2362d3Smrg#include <errno.h>
42de2362d3Smrg
430d16fef4Smrg#include "radeon_bo_helper.h"
44de2362d3Smrg#include "radeon_version.h"
450d16fef4Smrg#include "radeon_list.h"
46de2362d3Smrg
47de2362d3Smrg#include "radeon_bo_gem.h"
48de2362d3Smrg
490d16fef4Smrg#include <xf86Priv.h>
50de2362d3Smrg
51de2362d3Smrg#if DRI2INFOREC_VERSION >= 9
52de2362d3Smrg#define USE_DRI2_PRIME
53de2362d3Smrg#endif
54de2362d3Smrg
55de2362d3Smrg#define FALLBACK_SWAP_DELAY 16
56de2362d3Smrg
570d16fef4Smrg#include "radeon_glamor.h"
58de2362d3Smrg
59de2362d3Smrgtypedef DRI2BufferPtr BufferPtr;
60de2362d3Smrg
61de2362d3Smrgstruct dri2_buffer_priv {
62de2362d3Smrg    PixmapPtr   pixmap;
63de2362d3Smrg    unsigned int attachment;
64de2362d3Smrg    unsigned int refcnt;
65de2362d3Smrg};
66de2362d3Smrg
67de2362d3Smrg
680d16fef4Smrgstruct dri2_window_priv {
690d16fef4Smrg    xf86CrtcPtr crtc;
700d16fef4Smrg    int vblank_delta;
710d16fef4Smrg};
720d16fef4Smrg
730d16fef4Smrgstatic DevPrivateKeyRec dri2_window_private_key_rec;
740d16fef4Smrg#define dri2_window_private_key (&dri2_window_private_key_rec)
750d16fef4Smrg
760d16fef4Smrg#define get_dri2_window_priv(window) \
770d16fef4Smrg    ((struct dri2_window_priv*) \
780d16fef4Smrg     dixLookupPrivate(&(window)->devPrivates, dri2_window_private_key))
790d16fef4Smrg
800d16fef4Smrg
81de2362d3Smrgstatic PixmapPtr get_drawable_pixmap(DrawablePtr drawable)
82de2362d3Smrg{
83de2362d3Smrg    if (drawable->type == DRAWABLE_PIXMAP)
84de2362d3Smrg	return (PixmapPtr)drawable;
85de2362d3Smrg    else
86de2362d3Smrg	return (*drawable->pScreen->GetWindowPixmap)((WindowPtr)drawable);
87de2362d3Smrg}
88de2362d3Smrg
89de2362d3Smrg
90de2362d3Smrgstatic PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap)
91de2362d3Smrg{
92de2362d3Smrg	PixmapPtr old = get_drawable_pixmap(drawable);
93de2362d3Smrg#ifdef USE_GLAMOR
94de2362d3Smrg	ScreenPtr screen = drawable->pScreen;
95de2362d3Smrg	struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
96de2362d3Smrg	GCPtr gc;
97de2362d3Smrg
98de2362d3Smrg	/* With a glamor pixmap, 2D pixmaps are created in texture
99de2362d3Smrg	 * and without a static BO attached to it. To support DRI,
100de2362d3Smrg	 * we need to create a new textured-drm pixmap and
101de2362d3Smrg	 * need to copy the original content to this new textured-drm
102de2362d3Smrg	 * pixmap, and then convert the old pixmap to a coherent
103de2362d3Smrg	 * textured-drm pixmap which has a valid BO attached to it
104de2362d3Smrg	 * and also has a valid texture, thus both glamor and DRI2
105de2362d3Smrg	 * can access it.
106de2362d3Smrg	 *
107de2362d3Smrg	 */
108de2362d3Smrg
109de2362d3Smrg	/* Copy the current contents of the pixmap to the bo. */
110de2362d3Smrg	gc = GetScratchGC(drawable->depth, screen);
111de2362d3Smrg	if (gc) {
112de2362d3Smrg		ValidateGC(&pixmap->drawable, gc);
113de2362d3Smrg		gc->ops->CopyArea(&old->drawable, &pixmap->drawable,
114de2362d3Smrg				  gc,
115de2362d3Smrg				  0, 0,
116de2362d3Smrg				  old->drawable.width,
117de2362d3Smrg				  old->drawable.height,
118de2362d3Smrg				  0, 0);
119de2362d3Smrg		FreeScratchGC(gc);
120de2362d3Smrg	}
121de2362d3Smrg
122de2362d3Smrg	radeon_set_pixmap_private(pixmap, NULL);
123de2362d3Smrg
124de2362d3Smrg	/* And redirect the pixmap to the new bo (for 3D). */
125de2362d3Smrg	glamor_egl_exchange_buffers(old, pixmap);
126de2362d3Smrg	radeon_set_pixmap_private(old, priv);
127de2362d3Smrg	old->refcnt++;
128de2362d3Smrg
129de2362d3Smrg	screen->ModifyPixmapHeader(old,
130de2362d3Smrg				   old->drawable.width,
131de2362d3Smrg				   old->drawable.height,
132de2362d3Smrg				   0, 0,
1330d16fef4Smrg				   pixmap->devKind,
134de2362d3Smrg				   NULL);
1350d16fef4Smrg	old->devPrivate.ptr = NULL;
1360d16fef4Smrg
1370d16fef4Smrg	screen->DestroyPixmap(pixmap);
138de2362d3Smrg
139de2362d3Smrg#endif /* USE_GLAMOR*/
140de2362d3Smrg
141de2362d3Smrg	return old;
142de2362d3Smrg}
143de2362d3Smrg
1440d16fef4Smrg/* Get GEM flink name for a pixmap */
1450d16fef4Smrgstatic Bool
1460d16fef4Smrgradeon_get_flink_name(RADEONInfoPtr info, PixmapPtr pixmap, uint32_t *name)
1470d16fef4Smrg{
1480d16fef4Smrg    struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap);
1490d16fef4Smrg    struct drm_gem_flink flink;
1500d16fef4Smrg
1510d16fef4Smrg    if (bo)
1520d16fef4Smrg	return radeon_gem_get_kernel_name(bo, name) == 0;
1530d16fef4Smrg
1540d16fef4Smrg    if (radeon_get_pixmap_handle(pixmap, &flink.handle)) {
1550d16fef4Smrg	if (drmIoctl(info->dri2.drm_fd, DRM_IOCTL_GEM_FLINK, &flink) != 0)
1560d16fef4Smrg	    return FALSE;
1570d16fef4Smrg
1580d16fef4Smrg	*name = flink.name;
1590d16fef4Smrg	return TRUE;
1600d16fef4Smrg    }
1610d16fef4Smrg
1620d16fef4Smrg    return FALSE;
1630d16fef4Smrg}
164de2362d3Smrg
165de2362d3Smrgstatic BufferPtr
166de2362d3Smrgradeon_dri2_create_buffer2(ScreenPtr pScreen,
167de2362d3Smrg			   DrawablePtr drawable,
168de2362d3Smrg			   unsigned int attachment,
169de2362d3Smrg			   unsigned int format)
170de2362d3Smrg{
171de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
172de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
173de2362d3Smrg    BufferPtr buffers;
174de2362d3Smrg    struct dri2_buffer_priv *privates;
1750d16fef4Smrg    PixmapPtr pixmap;
176de2362d3Smrg    int flags;
177de2362d3Smrg    unsigned front_width;
178de2362d3Smrg    uint32_t tiling = 0;
179de2362d3Smrg    unsigned aligned_width = drawable->width;
180de2362d3Smrg    unsigned height = drawable->height;
181de2362d3Smrg    Bool is_glamor_pixmap = FALSE;
182de2362d3Smrg    int depth;
183de2362d3Smrg    int cpp;
184de2362d3Smrg
185de2362d3Smrg    if (format) {
186de2362d3Smrg	depth = format;
187de2362d3Smrg
188de2362d3Smrg	switch (depth) {
189de2362d3Smrg	case 15:
190de2362d3Smrg	    cpp = 2;
191de2362d3Smrg	    break;
192de2362d3Smrg	case 24:
193de2362d3Smrg	    cpp = 4;
194de2362d3Smrg	    break;
195de2362d3Smrg	default:
196de2362d3Smrg	    cpp = depth / 8;
197de2362d3Smrg	}
198de2362d3Smrg    } else {
199de2362d3Smrg	depth = drawable->depth;
200de2362d3Smrg	cpp = drawable->bitsPerPixel / 8;
201de2362d3Smrg    }
202de2362d3Smrg
2030d16fef4Smrg    front_width = pScreen->GetScreenPixmap(pScreen)->drawable.width;
204de2362d3Smrg
2050d16fef4Smrg    pixmap = NULL;
206de2362d3Smrg
207de2362d3Smrg    if (attachment == DRI2BufferFrontLeft) {
2080d16fef4Smrg	uint32_t handle;
2090d16fef4Smrg
210de2362d3Smrg        pixmap = get_drawable_pixmap(drawable);
211de2362d3Smrg	if (pScreen != pixmap->drawable.pScreen)
212de2362d3Smrg	    pixmap = NULL;
2130d16fef4Smrg	else if (info->use_glamor && !radeon_get_pixmap_handle(pixmap, &handle)) {
214de2362d3Smrg	    is_glamor_pixmap = TRUE;
215de2362d3Smrg	    aligned_width = pixmap->drawable.width;
216de2362d3Smrg	    height = pixmap->drawable.height;
217de2362d3Smrg	    pixmap = NULL;
218de2362d3Smrg	} else
219de2362d3Smrg	    pixmap->refcnt++;
220de2362d3Smrg    }
221de2362d3Smrg
222de2362d3Smrg    if (!pixmap && (is_glamor_pixmap || attachment != DRI2BufferFrontLeft)) {
223de2362d3Smrg	/* tile the back buffer */
224de2362d3Smrg	switch(attachment) {
225de2362d3Smrg	case DRI2BufferDepth:
226de2362d3Smrg	    /* macro is the preferred setting, but the 2D detiling for software
227de2362d3Smrg	     * fallbacks in mesa still has issues on some configurations
228de2362d3Smrg	     */
229de2362d3Smrg	    if (info->ChipFamily >= CHIP_FAMILY_R600) {
230de2362d3Smrg		if (info->allowColorTiling2D) {
231de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
232de2362d3Smrg		} else {
233de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
234de2362d3Smrg		}
235de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_CEDAR)
236de2362d3Smrg		    flags |= RADEON_CREATE_PIXMAP_SZBUFFER;
237de2362d3Smrg	    } else if (cpp == 2 && info->ChipFamily >= CHIP_FAMILY_R300)
238de2362d3Smrg		flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE;
239de2362d3Smrg	    else
240de2362d3Smrg		flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO;
241de2362d3Smrg	    if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON)
242de2362d3Smrg		flags |= RADEON_CREATE_PIXMAP_DEPTH;
243de2362d3Smrg	    break;
244de2362d3Smrg	case DRI2BufferDepthStencil:
245de2362d3Smrg	    /* macro is the preferred setting, but the 2D detiling for software
246de2362d3Smrg	     * fallbacks in mesa still has issues on some configurations
247de2362d3Smrg	     */
248de2362d3Smrg	    if (info->ChipFamily >= CHIP_FAMILY_R600) {
249de2362d3Smrg		if (info->allowColorTiling2D) {
250de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
251de2362d3Smrg		} else {
252de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
253de2362d3Smrg		}
254de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_CEDAR)
255de2362d3Smrg		    flags |= RADEON_CREATE_PIXMAP_SZBUFFER;
256de2362d3Smrg	    } else if (cpp == 2 && info->ChipFamily >= CHIP_FAMILY_R300)
257de2362d3Smrg		flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE;
258de2362d3Smrg	    else
259de2362d3Smrg		flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO;
260de2362d3Smrg	    if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON)
261de2362d3Smrg		flags |= RADEON_CREATE_PIXMAP_DEPTH;
262de2362d3Smrg
263de2362d3Smrg	    break;
264de2362d3Smrg	case DRI2BufferBackLeft:
265de2362d3Smrg	case DRI2BufferBackRight:
266de2362d3Smrg	case DRI2BufferFrontLeft:
267de2362d3Smrg	case DRI2BufferFrontRight:
268de2362d3Smrg	case DRI2BufferFakeFrontLeft:
269de2362d3Smrg	case DRI2BufferFakeFrontRight:
270de2362d3Smrg	    if (info->ChipFamily >= CHIP_FAMILY_R600) {
271de2362d3Smrg		if (info->allowColorTiling2D) {
272de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
273de2362d3Smrg		} else {
274de2362d3Smrg			flags = RADEON_CREATE_PIXMAP_TILING_MICRO;
275de2362d3Smrg		}
276de2362d3Smrg	    } else
277de2362d3Smrg		flags = RADEON_CREATE_PIXMAP_TILING_MACRO;
278de2362d3Smrg	    break;
279de2362d3Smrg	default:
280de2362d3Smrg	    flags = 0;
281de2362d3Smrg	}
282de2362d3Smrg
283de2362d3Smrg	if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO)
284de2362d3Smrg	    tiling |= RADEON_TILING_MICRO;
285de2362d3Smrg	if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE)
286de2362d3Smrg	    tiling |= RADEON_TILING_MICRO_SQUARE;
287de2362d3Smrg	if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO)
288de2362d3Smrg	    tiling |= RADEON_TILING_MACRO;
289de2362d3Smrg
290de2362d3Smrg	    if (aligned_width == front_width)
291de2362d3Smrg		aligned_width = pScrn->virtualX;
292de2362d3Smrg
293de2362d3Smrg	    pixmap = (*pScreen->CreatePixmap)(pScreen,
294de2362d3Smrg					      aligned_width,
295de2362d3Smrg					      height,
296de2362d3Smrg					      depth,
297de2362d3Smrg					      flags | RADEON_CREATE_PIXMAP_DRI2);
298de2362d3Smrg    }
299de2362d3Smrg
300de2362d3Smrg    buffers = calloc(1, sizeof *buffers);
301de2362d3Smrg    if (buffers == NULL)
302de2362d3Smrg        goto error;
303de2362d3Smrg
304de2362d3Smrg    if (pixmap) {
305de2362d3Smrg	if (!info->use_glamor) {
306de2362d3Smrg	    info->exa_force_create = TRUE;
307de2362d3Smrg	    exaMoveInPixmap(pixmap);
308de2362d3Smrg	    info->exa_force_create = FALSE;
309de2362d3Smrg	    if (exaGetPixmapDriverPrivate(pixmap) == NULL) {
310de2362d3Smrg		/* this happen if pixmap is non accelerable */
311de2362d3Smrg		goto error;
312de2362d3Smrg	    }
313de2362d3Smrg	}
314de2362d3Smrg
315de2362d3Smrg	if (is_glamor_pixmap)
316de2362d3Smrg	    pixmap = fixup_glamor(drawable, pixmap);
3170d16fef4Smrg	if (!radeon_get_flink_name(info, pixmap, &buffers->name))
318de2362d3Smrg	    goto error;
319de2362d3Smrg    }
320de2362d3Smrg
321de2362d3Smrg    privates = calloc(1, sizeof(struct dri2_buffer_priv));
322de2362d3Smrg    if (privates == NULL)
323de2362d3Smrg        goto error;
324de2362d3Smrg
325de2362d3Smrg    buffers->attachment = attachment;
326de2362d3Smrg    if (pixmap) {
327de2362d3Smrg	buffers->pitch = pixmap->devKind;
328de2362d3Smrg	buffers->cpp = cpp;
329de2362d3Smrg    }
330de2362d3Smrg    buffers->driverPrivate = privates;
331de2362d3Smrg    buffers->format = format;
332de2362d3Smrg    buffers->flags = 0; /* not tiled */
333de2362d3Smrg    privates->pixmap = pixmap;
334de2362d3Smrg    privates->attachment = attachment;
335de2362d3Smrg    privates->refcnt = 1;
336de2362d3Smrg
337de2362d3Smrg    return buffers;
338de2362d3Smrg
339de2362d3Smrgerror:
340de2362d3Smrg    free(buffers);
341de2362d3Smrg    if (pixmap)
342de2362d3Smrg        (*pScreen->DestroyPixmap)(pixmap);
343de2362d3Smrg    return NULL;
344de2362d3Smrg}
345de2362d3Smrg
346de2362d3SmrgDRI2BufferPtr
347de2362d3Smrgradeon_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment,
348de2362d3Smrg			   unsigned int format)
349de2362d3Smrg{
350de2362d3Smrg	return radeon_dri2_create_buffer2(pDraw->pScreen, pDraw,
351de2362d3Smrg					  attachment, format);
352de2362d3Smrg}
353de2362d3Smrg
354de2362d3Smrgstatic void
355de2362d3Smrgradeon_dri2_destroy_buffer2(ScreenPtr pScreen,
356de2362d3Smrg			    DrawablePtr drawable, BufferPtr buffers)
357de2362d3Smrg{
358de2362d3Smrg    if(buffers)
359de2362d3Smrg    {
360de2362d3Smrg        struct dri2_buffer_priv *private = buffers->driverPrivate;
361de2362d3Smrg
362de2362d3Smrg        /* Trying to free an already freed buffer is unlikely to end well */
363de2362d3Smrg        if (private->refcnt == 0) {
364de2362d3Smrg            ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
365de2362d3Smrg
366de2362d3Smrg            xf86DrvMsg(scrn->scrnIndex, X_WARNING,
367de2362d3Smrg                       "Attempted to destroy previously destroyed buffer.\
368de2362d3Smrg This is a programming error\n");
369de2362d3Smrg            return;
370de2362d3Smrg        }
371de2362d3Smrg
372de2362d3Smrg        private->refcnt--;
373de2362d3Smrg        if (private->refcnt == 0)
374de2362d3Smrg        {
375de2362d3Smrg	    if (private->pixmap)
376de2362d3Smrg                (*pScreen->DestroyPixmap)(private->pixmap);
377de2362d3Smrg
378de2362d3Smrg            free(buffers->driverPrivate);
379de2362d3Smrg            free(buffers);
380de2362d3Smrg        }
381de2362d3Smrg    }
382de2362d3Smrg}
383de2362d3Smrg
384de2362d3Smrgvoid
385de2362d3Smrgradeon_dri2_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buf)
386de2362d3Smrg{
387de2362d3Smrg    radeon_dri2_destroy_buffer2(pDraw->pScreen, pDraw, buf);
388de2362d3Smrg}
389de2362d3Smrg
390de2362d3Smrg
391de2362d3Smrgstatic inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable)
392de2362d3Smrg{
393de2362d3Smrg    if (drawable->type == DRAWABLE_PIXMAP)
394de2362d3Smrg        return (PixmapPtr)drawable;
395de2362d3Smrg    else {
396de2362d3Smrg        struct _Window *pWin = (struct _Window *)drawable;
397de2362d3Smrg        return drawable->pScreen->GetWindowPixmap(pWin);
398de2362d3Smrg    }
399de2362d3Smrg}
400de2362d3Smrgstatic void
401de2362d3Smrgradeon_dri2_copy_region2(ScreenPtr pScreen,
402de2362d3Smrg			 DrawablePtr drawable,
403de2362d3Smrg			 RegionPtr region,
404de2362d3Smrg			 BufferPtr dest_buffer,
405de2362d3Smrg			 BufferPtr src_buffer)
406de2362d3Smrg{
407de2362d3Smrg    struct dri2_buffer_priv *src_private = src_buffer->driverPrivate;
408de2362d3Smrg    struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate;
409de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
410de2362d3Smrg    DrawablePtr src_drawable;
411de2362d3Smrg    DrawablePtr dst_drawable;
412de2362d3Smrg    RegionPtr copy_clip;
413de2362d3Smrg    GCPtr gc;
414de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
415de2362d3Smrg    Bool vsync;
416de2362d3Smrg    Bool translate = FALSE;
417de2362d3Smrg    int off_x = 0, off_y = 0;
418de2362d3Smrg    PixmapPtr dst_ppix;
419de2362d3Smrg
420de2362d3Smrg    dst_ppix = dst_private->pixmap;
421de2362d3Smrg    src_drawable = &src_private->pixmap->drawable;
422de2362d3Smrg    dst_drawable = &dst_private->pixmap->drawable;
423de2362d3Smrg
424de2362d3Smrg    if (src_private->attachment == DRI2BufferFrontLeft) {
425de2362d3Smrg#ifdef USE_DRI2_PRIME
426de2362d3Smrg	if (drawable->pScreen != pScreen) {
427de2362d3Smrg	    src_drawable = DRI2UpdatePrime(drawable, src_buffer);
428de2362d3Smrg	    if (!src_drawable)
429de2362d3Smrg		return;
430de2362d3Smrg	} else
431de2362d3Smrg#endif
432de2362d3Smrg	    src_drawable = drawable;
433de2362d3Smrg    }
434de2362d3Smrg    if (dst_private->attachment == DRI2BufferFrontLeft) {
435de2362d3Smrg#ifdef USE_DRI2_PRIME
436de2362d3Smrg	if (drawable->pScreen != pScreen) {
437de2362d3Smrg	    dst_drawable = DRI2UpdatePrime(drawable, dest_buffer);
438de2362d3Smrg	    if (!dst_drawable)
439de2362d3Smrg		return;
440de2362d3Smrg	    dst_ppix = (PixmapPtr)dst_drawable;
441de2362d3Smrg	    if (dst_drawable != drawable)
442de2362d3Smrg		translate = TRUE;
443de2362d3Smrg	} else
444de2362d3Smrg#endif
445de2362d3Smrg	    dst_drawable = drawable;
446de2362d3Smrg    }
447de2362d3Smrg
448de2362d3Smrg    if (translate && drawable->type == DRAWABLE_WINDOW) {
449de2362d3Smrg	PixmapPtr pPix = GetDrawablePixmap(drawable);
450de2362d3Smrg
451de2362d3Smrg	off_x = drawable->x - pPix->screen_x;
452de2362d3Smrg	off_y = drawable->y - pPix->screen_y;
453de2362d3Smrg    }
454de2362d3Smrg    gc = GetScratchGC(dst_drawable->depth, pScreen);
455de2362d3Smrg    copy_clip = REGION_CREATE(pScreen, NULL, 0);
456de2362d3Smrg    REGION_COPY(pScreen, copy_clip, region);
457de2362d3Smrg
458de2362d3Smrg    if (translate) {
459de2362d3Smrg	REGION_TRANSLATE(pScreen, copy_clip, off_x, off_y);
460de2362d3Smrg    }
461de2362d3Smrg
462de2362d3Smrg    (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0);
463de2362d3Smrg    ValidateGC(dst_drawable, gc);
464de2362d3Smrg
465de2362d3Smrg    /* If this is a full buffer swap or frontbuffer flush, throttle on the
466de2362d3Smrg     * previous one
467de2362d3Smrg     */
468de2362d3Smrg    if (dst_private->attachment == DRI2BufferFrontLeft) {
469de2362d3Smrg	if (REGION_NUM_RECTS(region) == 1) {
470de2362d3Smrg	    BoxPtr extents = REGION_EXTENTS(pScreen, region);
471de2362d3Smrg
472de2362d3Smrg	    if (extents->x1 == 0 && extents->y1 == 0 &&
473de2362d3Smrg		extents->x2 == drawable->width &&
474de2362d3Smrg		extents->y2 == drawable->height) {
475de2362d3Smrg		struct radeon_bo *bo = radeon_get_pixmap_bo(dst_ppix);
476de2362d3Smrg
477de2362d3Smrg		if (bo)
478de2362d3Smrg		    radeon_bo_wait(bo);
479de2362d3Smrg	    }
480de2362d3Smrg	}
481de2362d3Smrg    }
482de2362d3Smrg
483de2362d3Smrg    vsync = info->accel_state->vsync;
484de2362d3Smrg
485de2362d3Smrg    /* Driver option "SwapbuffersWait" defines if we vsync DRI2 copy-swaps. */
486de2362d3Smrg    info->accel_state->vsync = info->swapBuffersWait;
487de2362d3Smrg    info->accel_state->force = TRUE;
488de2362d3Smrg
489de2362d3Smrg    (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc,
490de2362d3Smrg                         0, 0, drawable->width, drawable->height, off_x, off_y);
491de2362d3Smrg
492de2362d3Smrg    info->accel_state->force = FALSE;
493de2362d3Smrg    info->accel_state->vsync = vsync;
494de2362d3Smrg
495de2362d3Smrg    FreeScratchGC(gc);
496de2362d3Smrg}
497de2362d3Smrg
498de2362d3Smrgvoid
499de2362d3Smrgradeon_dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
500de2362d3Smrg			 DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
501de2362d3Smrg{
502de2362d3Smrg    return radeon_dri2_copy_region2(pDraw->pScreen, pDraw, pRegion,
503de2362d3Smrg				     pDstBuffer, pSrcBuffer);
504de2362d3Smrg}
505de2362d3Smrg
506de2362d3Smrgenum DRI2FrameEventType {
507de2362d3Smrg    DRI2_SWAP,
508de2362d3Smrg    DRI2_FLIP,
509de2362d3Smrg    DRI2_WAITMSC,
510de2362d3Smrg};
511de2362d3Smrg
512de2362d3Smrgtypedef struct _DRI2FrameEvent {
513de2362d3Smrg    XID drawable_id;
514de2362d3Smrg    ClientPtr client;
515de2362d3Smrg    enum DRI2FrameEventType type;
5160d16fef4Smrg    unsigned frame;
517de2362d3Smrg    xf86CrtcPtr crtc;
5180d16fef4Smrg    OsTimerPtr timer;
5190d16fef4Smrg    uintptr_t drm_queue_seq;
520de2362d3Smrg
521de2362d3Smrg    /* for swaps & flips only */
522de2362d3Smrg    DRI2SwapEventPtr event_complete;
523de2362d3Smrg    void *event_data;
524de2362d3Smrg    DRI2BufferPtr front;
525de2362d3Smrg    DRI2BufferPtr back;
526de2362d3Smrg} DRI2FrameEventRec, *DRI2FrameEventPtr;
527de2362d3Smrg
528de2362d3Smrgstatic int DRI2InfoCnt;
529de2362d3Smrg
530de2362d3Smrgstatic void
531de2362d3Smrgradeon_dri2_ref_buffer(BufferPtr buffer)
532de2362d3Smrg{
533de2362d3Smrg    struct dri2_buffer_priv *private = buffer->driverPrivate;
534de2362d3Smrg    private->refcnt++;
535de2362d3Smrg}
536de2362d3Smrg
537de2362d3Smrgstatic void
538de2362d3Smrgradeon_dri2_unref_buffer(BufferPtr buffer)
539de2362d3Smrg{
540de2362d3Smrg    if (buffer) {
541de2362d3Smrg        struct dri2_buffer_priv *private = buffer->driverPrivate;
542de2362d3Smrg        radeon_dri2_destroy_buffer(&(private->pixmap->drawable), buffer);
543de2362d3Smrg    }
544de2362d3Smrg}
545de2362d3Smrg
546de2362d3Smrgstatic void
547de2362d3Smrgradeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata)
548de2362d3Smrg{
549de2362d3Smrg    NewClientInfoRec *clientinfo = calldata;
550de2362d3Smrg    ClientPtr pClient = clientinfo->client;
551de2362d3Smrg
552de2362d3Smrg    switch (pClient->clientState) {
553de2362d3Smrg    case ClientStateRetained:
554de2362d3Smrg    case ClientStateGone:
5550d16fef4Smrg        radeon_drm_abort_client(pClient);
556de2362d3Smrg        break;
557de2362d3Smrg    default:
558de2362d3Smrg        break;
559de2362d3Smrg    }
560de2362d3Smrg}
561de2362d3Smrg
5620d16fef4Smrg/*
5630d16fef4Smrg * Get current frame count delta for the specified drawable and CRTC
5640d16fef4Smrg */
5650d16fef4Smrgstatic uint32_t radeon_get_msc_delta(DrawablePtr pDraw, xf86CrtcPtr crtc)
5660d16fef4Smrg{
5670d16fef4Smrg    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
5680d16fef4Smrg
5690d16fef4Smrg    if (pDraw && pDraw->type == DRAWABLE_WINDOW)
5700d16fef4Smrg	return drmmode_crtc->interpolated_vblanks +
5710d16fef4Smrg	    get_dri2_window_priv((WindowPtr)pDraw)->vblank_delta;
5720d16fef4Smrg
5730d16fef4Smrg    return drmmode_crtc->interpolated_vblanks;
5740d16fef4Smrg}
5750d16fef4Smrg
5760d16fef4Smrg/*
5770d16fef4Smrg * Get current frame count and timestamp of the specified CRTC
5780d16fef4Smrg */
5790d16fef4Smrgstatic Bool radeon_dri2_get_crtc_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)
5800d16fef4Smrg{
5810d16fef4Smrg    if (!radeon_crtc_is_enabled(crtc) ||
5820d16fef4Smrg	 drmmode_crtc_get_ust_msc(crtc, ust, msc) != Success) {
5830d16fef4Smrg	/* CRTC is not running, extrapolate MSC and timestamp */
5840d16fef4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
5850d16fef4Smrg	ScrnInfoPtr scrn = crtc->scrn;
5860d16fef4Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
5870d16fef4Smrg	CARD64 now, delta_t, delta_seq;
5880d16fef4Smrg
5890d16fef4Smrg	if (!drmmode_crtc->dpms_last_ust)
5900d16fef4Smrg	    return FALSE;
5910d16fef4Smrg
5920d16fef4Smrg	if (drmmode_get_current_ust(info->dri2.drm_fd, &now) != 0) {
5930d16fef4Smrg	    xf86DrvMsg(scrn->scrnIndex, X_ERROR,
5940d16fef4Smrg		       "%s cannot get current time\n", __func__);
5950d16fef4Smrg	    return FALSE;
5960d16fef4Smrg	}
5970d16fef4Smrg
5980d16fef4Smrg	delta_t = now - drmmode_crtc->dpms_last_ust;
5990d16fef4Smrg	delta_seq = delta_t * drmmode_crtc->dpms_last_fps;
6000d16fef4Smrg	delta_seq /= 1000000;
6010d16fef4Smrg	*ust = drmmode_crtc->dpms_last_ust;
6020d16fef4Smrg	delta_t = delta_seq * 1000000;
6030d16fef4Smrg	delta_t /= drmmode_crtc->dpms_last_fps;
6040d16fef4Smrg	*ust += delta_t;
6050d16fef4Smrg	*msc = drmmode_crtc->dpms_last_seq;
6060d16fef4Smrg	*msc += delta_seq;
6070d16fef4Smrg    }
6080d16fef4Smrg
6090d16fef4Smrg    return TRUE;
6100d16fef4Smrg}
6110d16fef4Smrg
612de2362d3Smrgstatic
613de2362d3Smrgxf86CrtcPtr radeon_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled)
614de2362d3Smrg{
615de2362d3Smrg    ScreenPtr pScreen = pDraw->pScreen;
616de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
6170d16fef4Smrg    xf86CrtcPtr crtc = radeon_pick_best_crtc(pScrn, consider_disabled,
6180d16fef4Smrg					      pDraw->x, pDraw->x + pDraw->width,
6190d16fef4Smrg					      pDraw->y, pDraw->y + pDraw->height);
620de2362d3Smrg
6210d16fef4Smrg    if (crtc && pDraw->type == DRAWABLE_WINDOW) {
6220d16fef4Smrg	struct dri2_window_priv *priv = get_dri2_window_priv((WindowPtr)pDraw);
623de2362d3Smrg
6240d16fef4Smrg	if (priv->crtc && priv->crtc != crtc) {
6250d16fef4Smrg	    CARD64 ust, mscold, mscnew;
6260d16fef4Smrg
6270d16fef4Smrg	    if (radeon_dri2_get_crtc_msc(priv->crtc, &ust, &mscold) &&
6280d16fef4Smrg		radeon_dri2_get_crtc_msc(crtc, &ust, &mscnew))
6290d16fef4Smrg		priv->vblank_delta += mscold - mscnew;
6300d16fef4Smrg	}
6310d16fef4Smrg
6320d16fef4Smrg	priv->crtc = crtc;
6330d16fef4Smrg    }
6340d16fef4Smrg
6350d16fef4Smrg    return crtc;
6360d16fef4Smrg}
6370d16fef4Smrg
6380d16fef4Smrgstatic void
6390d16fef4Smrgradeon_dri2_flip_event_abort(xf86CrtcPtr crtc, void *event_data)
6400d16fef4Smrg{
6410d16fef4Smrg    RADEONInfoPtr info = RADEONPTR(crtc->scrn);
6420d16fef4Smrg
6430d16fef4Smrg    info->drmmode.dri2_flipping = FALSE;
6440d16fef4Smrg    free(event_data);
6450d16fef4Smrg}
6460d16fef4Smrg
6470d16fef4Smrgstatic void
6480d16fef4Smrgradeon_dri2_flip_event_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
6490d16fef4Smrg			       void *event_data)
6500d16fef4Smrg{
6510d16fef4Smrg    DRI2FrameEventPtr flip = event_data;
6520d16fef4Smrg    ScrnInfoPtr scrn = crtc->scrn;
6530d16fef4Smrg    unsigned tv_sec, tv_usec;
6540d16fef4Smrg    DrawablePtr drawable;
6550d16fef4Smrg    ScreenPtr screen;
6560d16fef4Smrg    int status;
6570d16fef4Smrg    PixmapPtr pixmap;
6580d16fef4Smrg
6590d16fef4Smrg    status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient,
6600d16fef4Smrg			       M_ANY, DixWriteAccess);
6610d16fef4Smrg    if (status != Success)
6620d16fef4Smrg	goto abort;
6630d16fef4Smrg
6640d16fef4Smrg    frame += radeon_get_msc_delta(drawable, crtc);
6650d16fef4Smrg
6660d16fef4Smrg    screen = scrn->pScreen;
6670d16fef4Smrg    pixmap = screen->GetScreenPixmap(screen);
6680d16fef4Smrg    xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
6690d16fef4Smrg		   "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n",
6700d16fef4Smrg		   __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4);
6710d16fef4Smrg
6720d16fef4Smrg    tv_sec = usec / 1000000;
6730d16fef4Smrg    tv_usec = usec % 1000000;
6740d16fef4Smrg
6750d16fef4Smrg    /* We assume our flips arrive in order, so we don't check the frame */
6760d16fef4Smrg    switch (flip->type) {
6770d16fef4Smrg    case DRI2_SWAP:
6780d16fef4Smrg	/* Check for too small vblank count of pageflip completion, taking wraparound
6790d16fef4Smrg	 * into account. This usually means some defective kms pageflip completion,
6800d16fef4Smrg	 * causing wrong (msc, ust) return values and possible visual corruption.
6810d16fef4Smrg	 */
6820d16fef4Smrg	if ((frame < flip->frame) && (flip->frame - frame < 5)) {
6830d16fef4Smrg	    xf86DrvMsg(scrn->scrnIndex, X_WARNING,
6840d16fef4Smrg		       "%s: Pageflip completion event has impossible msc %u < target_msc %u\n",
6850d16fef4Smrg		       __func__, frame, flip->frame);
6860d16fef4Smrg	    /* All-Zero values signal failure of (msc, ust) timestamping to client. */
6870d16fef4Smrg	    frame = tv_sec = tv_usec = 0;
6880d16fef4Smrg	}
6890d16fef4Smrg
6900d16fef4Smrg	DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
6910d16fef4Smrg			 DRI2_FLIP_COMPLETE, flip->event_complete,
6920d16fef4Smrg			 flip->event_data);
6930d16fef4Smrg	break;
6940d16fef4Smrg    default:
6950d16fef4Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__);
6960d16fef4Smrg	/* Unknown type */
6970d16fef4Smrg	break;
6980d16fef4Smrg    }
6990d16fef4Smrg
7000d16fef4Smrgabort:
7010d16fef4Smrg    radeon_dri2_flip_event_abort(crtc, event_data);
702de2362d3Smrg}
703de2362d3Smrg
704de2362d3Smrgstatic Bool
7050d16fef4Smrgradeon_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client,
706de2362d3Smrg			  DrawablePtr draw, DRI2BufferPtr front,
707de2362d3Smrg			  DRI2BufferPtr back, DRI2SwapEventPtr func,
708de2362d3Smrg			  void *data, unsigned int target_msc)
709de2362d3Smrg{
7100d16fef4Smrg    ScrnInfoPtr scrn = crtc->scrn;
7110d16fef4Smrg    RADEONInfoPtr info = RADEONPTR(scrn);
712de2362d3Smrg    struct dri2_buffer_priv *back_priv;
713de2362d3Smrg    struct radeon_bo *bo;
714de2362d3Smrg    DRI2FrameEventPtr flip_info;
7150d16fef4Smrg    int ref_crtc_hw_id = drmmode_get_crtc_id(crtc);
716de2362d3Smrg
717de2362d3Smrg    flip_info = calloc(1, sizeof(DRI2FrameEventRec));
718de2362d3Smrg    if (!flip_info)
719de2362d3Smrg	return FALSE;
720de2362d3Smrg
721de2362d3Smrg    flip_info->drawable_id = draw->id;
722de2362d3Smrg    flip_info->client = client;
723de2362d3Smrg    flip_info->type = DRI2_SWAP;
724de2362d3Smrg    flip_info->event_complete = func;
725de2362d3Smrg    flip_info->event_data = data;
726de2362d3Smrg    flip_info->frame = target_msc;
727de2362d3Smrg    flip_info->crtc = crtc;
728de2362d3Smrg
729de2362d3Smrg    xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
730de2362d3Smrg		   "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info);
731de2362d3Smrg
732de2362d3Smrg    /* Page flip the full screen buffer */
733de2362d3Smrg    back_priv = back->driverPrivate;
734de2362d3Smrg    bo = radeon_get_pixmap_bo(back_priv->pixmap);
735de2362d3Smrg
7360d16fef4Smrg    if (radeon_do_pageflip(scrn, client, bo->handle,
7370d16fef4Smrg			   RADEON_DRM_QUEUE_ID_DEFAULT, flip_info,
7380d16fef4Smrg			   ref_crtc_hw_id,
7390d16fef4Smrg			   radeon_dri2_flip_event_handler,
7400d16fef4Smrg			   radeon_dri2_flip_event_abort)) {
7410d16fef4Smrg	info->drmmode.dri2_flipping = TRUE;
7420d16fef4Smrg	return TRUE;
7430d16fef4Smrg    }
7440d16fef4Smrg
7450d16fef4Smrg    return FALSE;
746de2362d3Smrg}
747de2362d3Smrg
748de2362d3Smrgstatic Bool
749de2362d3Smrgupdate_front(DrawablePtr draw, DRI2BufferPtr front)
750de2362d3Smrg{
751de2362d3Smrg    PixmapPtr pixmap;
752de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(draw->pScreen));
753de2362d3Smrg    struct dri2_buffer_priv *priv = front->driverPrivate;
754de2362d3Smrg
755de2362d3Smrg    pixmap = get_drawable_pixmap(draw);
756de2362d3Smrg    pixmap->refcnt++;
757de2362d3Smrg
758de2362d3Smrg    if (!info->use_glamor)
759de2362d3Smrg	exaMoveInPixmap(pixmap);
7600d16fef4Smrg    if (!radeon_get_flink_name(info, pixmap, &front->name)) {
761de2362d3Smrg	(*draw->pScreen->DestroyPixmap)(pixmap);
762de2362d3Smrg	return FALSE;
763de2362d3Smrg    }
764de2362d3Smrg    (*draw->pScreen->DestroyPixmap)(priv->pixmap);
765de2362d3Smrg    front->pitch = pixmap->devKind;
766de2362d3Smrg    front->cpp = pixmap->drawable.bitsPerPixel / 8;
767de2362d3Smrg    priv->pixmap = pixmap;
768de2362d3Smrg
769de2362d3Smrg    return TRUE;
770de2362d3Smrg}
771de2362d3Smrg
772de2362d3Smrgstatic Bool
773de2362d3Smrgcan_exchange(ScrnInfoPtr pScrn, DrawablePtr draw,
774de2362d3Smrg	     DRI2BufferPtr front, DRI2BufferPtr back)
775de2362d3Smrg{
776de2362d3Smrg    struct dri2_buffer_priv *front_priv = front->driverPrivate;
777de2362d3Smrg    struct dri2_buffer_priv *back_priv = back->driverPrivate;
778de2362d3Smrg    PixmapPtr front_pixmap;
779de2362d3Smrg    PixmapPtr back_pixmap = back_priv->pixmap;
780de2362d3Smrg    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
781de2362d3Smrg    int i;
782de2362d3Smrg
783de2362d3Smrg    for (i = 0; i < xf86_config->num_crtc; i++) {
784de2362d3Smrg	xf86CrtcPtr crtc = xf86_config->crtc[i];
785de2362d3Smrg	if (crtc->enabled && crtc->rotatedData)
786de2362d3Smrg	    return FALSE;
787de2362d3Smrg    }
788de2362d3Smrg
789de2362d3Smrg    if (!update_front(draw, front))
790de2362d3Smrg	return FALSE;
791de2362d3Smrg
792de2362d3Smrg    front_pixmap = front_priv->pixmap;
793de2362d3Smrg
794de2362d3Smrg    if (front_pixmap->drawable.width != back_pixmap->drawable.width)
795de2362d3Smrg	return FALSE;
796de2362d3Smrg
797de2362d3Smrg    if (front_pixmap->drawable.height != back_pixmap->drawable.height)
798de2362d3Smrg	return FALSE;
799de2362d3Smrg
800de2362d3Smrg    if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel)
801de2362d3Smrg	return FALSE;
802de2362d3Smrg
803de2362d3Smrg    if (front_pixmap->devKind != back_pixmap->devKind)
804de2362d3Smrg	return FALSE;
805de2362d3Smrg
806de2362d3Smrg    return TRUE;
807de2362d3Smrg}
808de2362d3Smrg
809de2362d3Smrgstatic Bool
810de2362d3Smrgcan_flip(ScrnInfoPtr pScrn, DrawablePtr draw,
811de2362d3Smrg	 DRI2BufferPtr front, DRI2BufferPtr back)
812de2362d3Smrg{
8130d16fef4Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
8140d16fef4Smrg
815de2362d3Smrg    return draw->type == DRAWABLE_WINDOW &&
8160d16fef4Smrg	   info->allowPageFlip &&
8170d16fef4Smrg	   !info->hwcursor_disabled &&
8180d16fef4Smrg	   !info->drmmode.present_flipping &&
819de2362d3Smrg	   pScrn->vtSema &&
820de2362d3Smrg	   DRI2CanFlip(draw) &&
821de2362d3Smrg	   can_exchange(pScrn, draw, front, back);
822de2362d3Smrg}
823de2362d3Smrg
824de2362d3Smrgstatic void
825de2362d3Smrgradeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
826de2362d3Smrg{
827de2362d3Smrg    struct dri2_buffer_priv *front_priv = front->driverPrivate;
828de2362d3Smrg    struct dri2_buffer_priv *back_priv = back->driverPrivate;
829de2362d3Smrg    struct radeon_bo *front_bo, *back_bo;
830de2362d3Smrg    ScreenPtr screen;
831de2362d3Smrg    RADEONInfoPtr info;
832de2362d3Smrg    RegionRec region;
833de2362d3Smrg    int tmp;
834de2362d3Smrg
835de2362d3Smrg    region.extents.x1 = region.extents.y1 = 0;
836de2362d3Smrg    region.extents.x2 = front_priv->pixmap->drawable.width;
837de2362d3Smrg    region.extents.y2 = front_priv->pixmap->drawable.width;
838de2362d3Smrg    region.data = NULL;
839de2362d3Smrg    DamageRegionAppend(&front_priv->pixmap->drawable, &region);
840de2362d3Smrg
841de2362d3Smrg    /* Swap BO names so DRI works */
842de2362d3Smrg    tmp = front->name;
843de2362d3Smrg    front->name = back->name;
844de2362d3Smrg    back->name = tmp;
845de2362d3Smrg
846de2362d3Smrg    /* Swap pixmap bos */
847de2362d3Smrg    front_bo = radeon_get_pixmap_bo(front_priv->pixmap);
848de2362d3Smrg    back_bo = radeon_get_pixmap_bo(back_priv->pixmap);
849de2362d3Smrg    radeon_set_pixmap_bo(front_priv->pixmap, back_bo);
850de2362d3Smrg    radeon_set_pixmap_bo(back_priv->pixmap, front_bo);
851de2362d3Smrg
852de2362d3Smrg    /* Do we need to update the Screen? */
853de2362d3Smrg    screen = draw->pScreen;
854de2362d3Smrg    info = RADEONPTR(xf86ScreenToScrn(screen));
855de2362d3Smrg    if (front_bo == info->front_bo) {
856de2362d3Smrg	radeon_bo_ref(back_bo);
857de2362d3Smrg	radeon_bo_unref(info->front_bo);
858de2362d3Smrg	info->front_bo = back_bo;
859de2362d3Smrg	radeon_set_pixmap_bo(screen->GetScreenPixmap(screen), back_bo);
860de2362d3Smrg    }
861de2362d3Smrg
862de2362d3Smrg    radeon_glamor_exchange_buffers(front_priv->pixmap, back_priv->pixmap);
863de2362d3Smrg
864de2362d3Smrg    DamageRegionProcessPending(&front_priv->pixmap->drawable);
865de2362d3Smrg}
866de2362d3Smrg
8670d16fef4Smrgstatic void radeon_dri2_frame_event_abort(xf86CrtcPtr crtc, void *event_data)
868de2362d3Smrg{
869de2362d3Smrg    DRI2FrameEventPtr event = event_data;
8700d16fef4Smrg
8710d16fef4Smrg    TimerCancel(event->timer);
8720d16fef4Smrg    TimerFree(event->timer);
8730d16fef4Smrg    radeon_dri2_unref_buffer(event->front);
8740d16fef4Smrg    radeon_dri2_unref_buffer(event->back);
8750d16fef4Smrg    free(event);
8760d16fef4Smrg}
8770d16fef4Smrg
8780d16fef4Smrgstatic void radeon_dri2_frame_event_handler(xf86CrtcPtr crtc, uint32_t seq,
8790d16fef4Smrg					    uint64_t usec, void *event_data)
8800d16fef4Smrg{
8810d16fef4Smrg    DRI2FrameEventPtr event = event_data;
8820d16fef4Smrg    ScrnInfoPtr scrn = crtc->scrn;
883de2362d3Smrg    DrawablePtr drawable;
884de2362d3Smrg    int status;
885de2362d3Smrg    int swap_type;
886de2362d3Smrg    BoxRec box;
887de2362d3Smrg    RegionRec region;
888de2362d3Smrg
889de2362d3Smrg    status = dixLookupDrawable(&drawable, event->drawable_id, serverClient,
890de2362d3Smrg                               M_ANY, DixWriteAccess);
891de2362d3Smrg    if (status != Success)
892de2362d3Smrg        goto cleanup;
893de2362d3Smrg
8940d16fef4Smrg    seq += radeon_get_msc_delta(drawable, crtc);
895de2362d3Smrg
896de2362d3Smrg    switch (event->type) {
897de2362d3Smrg    case DRI2_FLIP:
898de2362d3Smrg	if (can_flip(scrn, drawable, event->front, event->back) &&
8990d16fef4Smrg	    radeon_dri2_schedule_flip(crtc,
900de2362d3Smrg				      event->client,
901de2362d3Smrg				      drawable,
902de2362d3Smrg				      event->front,
903de2362d3Smrg				      event->back,
904de2362d3Smrg				      event->event_complete,
905de2362d3Smrg				      event->event_data,
906de2362d3Smrg				      event->frame)) {
907de2362d3Smrg	    radeon_dri2_exchange_buffers(drawable, event->front, event->back);
908de2362d3Smrg	    break;
909de2362d3Smrg	}
910de2362d3Smrg	/* else fall through to exchange/blit */
911de2362d3Smrg    case DRI2_SWAP:
912de2362d3Smrg	if (DRI2CanExchange(drawable) &&
913de2362d3Smrg	    can_exchange(scrn, drawable, event->front, event->back)) {
914de2362d3Smrg	    radeon_dri2_exchange_buffers(drawable, event->front, event->back);
915de2362d3Smrg	    swap_type = DRI2_EXCHANGE_COMPLETE;
916de2362d3Smrg	} else {
917de2362d3Smrg	    box.x1 = 0;
918de2362d3Smrg	    box.y1 = 0;
919de2362d3Smrg	    box.x2 = drawable->width;
920de2362d3Smrg	    box.y2 = drawable->height;
921de2362d3Smrg	    REGION_INIT(pScreen, &region, &box, 0);
922de2362d3Smrg	    radeon_dri2_copy_region(drawable, &region, event->front, event->back);
923de2362d3Smrg	    swap_type = DRI2_BLIT_COMPLETE;
924de2362d3Smrg	}
925de2362d3Smrg
9260d16fef4Smrg        DRI2SwapComplete(event->client, drawable, seq, usec / 1000000,
9270d16fef4Smrg			 usec % 1000000, swap_type, event->event_complete,
9280d16fef4Smrg			 event->event_data);
929de2362d3Smrg
930de2362d3Smrg        break;
931de2362d3Smrg    case DRI2_WAITMSC:
9320d16fef4Smrg        DRI2WaitMSCComplete(event->client, drawable, seq, usec / 1000000,
9330d16fef4Smrg			    usec % 1000000);
934de2362d3Smrg        break;
935de2362d3Smrg    default:
936de2362d3Smrg        /* Unknown type */
937de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
938de2362d3Smrg                "%s: unknown vblank event received\n", __func__);
939de2362d3Smrg        break;
940de2362d3Smrg    }
941de2362d3Smrg
942de2362d3Smrgcleanup:
9430d16fef4Smrg    radeon_dri2_frame_event_abort(crtc, event_data);
944de2362d3Smrg}
945de2362d3Smrg
946de2362d3SmrgdrmVBlankSeqType radeon_populate_vbl_request_type(xf86CrtcPtr crtc)
947de2362d3Smrg{
948de2362d3Smrg    drmVBlankSeqType type = 0;
949de2362d3Smrg    int crtc_id = drmmode_get_crtc_id(crtc);
950de2362d3Smrg
951de2362d3Smrg    if (crtc_id == 1)
952de2362d3Smrg        type |= DRM_VBLANK_SECONDARY;
953de2362d3Smrg    else if (crtc_id > 1)
954de2362d3Smrg#ifdef DRM_VBLANK_HIGH_CRTC_SHIFT
955de2362d3Smrg	type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) &
956de2362d3Smrg		DRM_VBLANK_HIGH_CRTC_MASK;
957de2362d3Smrg#else
958de2362d3Smrg	ErrorF("radeon driver bug: %s called for CRTC %d > 1, but "
959de2362d3Smrg	       "DRM_VBLANK_HIGH_CRTC_MASK not defined at build time\n",
960de2362d3Smrg	       __func__, crtc_id);
961de2362d3Smrg#endif
962de2362d3Smrg
963de2362d3Smrg    return type;
964de2362d3Smrg}
965de2362d3Smrg
966de2362d3Smrg/*
967de2362d3Smrg * This function should be called on a disabled CRTC only (i.e., CRTC
968de2362d3Smrg * in DPMS-off state). It will calculate the delay necessary to reach
969de2362d3Smrg * target_msc from present time if the CRTC were running.
970de2362d3Smrg */
971de2362d3Smrgstatic
972de2362d3SmrgCARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc,
973de2362d3Smrg					 CARD64 divisor, CARD64 remainder)
974de2362d3Smrg{
975de2362d3Smrg    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
976de2362d3Smrg    ScrnInfoPtr pScrn = crtc->scrn;
977de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
978de2362d3Smrg    int nominal_frame_rate = drmmode_crtc->dpms_last_fps;
979de2362d3Smrg    CARD64 last_vblank_ust = drmmode_crtc->dpms_last_ust;
980de2362d3Smrg    uint32_t last_vblank_seq = drmmode_crtc->dpms_last_seq;
981de2362d3Smrg    CARD64 now, target_time, delta_t;
982de2362d3Smrg    int64_t d, delta_seq;
983de2362d3Smrg    int ret;
984de2362d3Smrg    CARD32 d_ms;
985de2362d3Smrg
986de2362d3Smrg    if (!last_vblank_ust) {
987de2362d3Smrg	*target_msc = 0;
988de2362d3Smrg	return FALLBACK_SWAP_DELAY;
989de2362d3Smrg    }
990de2362d3Smrg    ret = drmmode_get_current_ust(info->dri2.drm_fd, &now);
991de2362d3Smrg    if (ret) {
992de2362d3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
993de2362d3Smrg		   "%s cannot get current time\n", __func__);
994de2362d3Smrg	*target_msc = 0;
995de2362d3Smrg	return FALLBACK_SWAP_DELAY;
996de2362d3Smrg    }
9970d16fef4Smrg    delta_seq = *target_msc - last_vblank_seq;
998de2362d3Smrg    delta_seq *= 1000000;
999de2362d3Smrg    target_time = last_vblank_ust;
1000de2362d3Smrg    target_time += delta_seq / nominal_frame_rate;
1001de2362d3Smrg    d = target_time - now;
1002de2362d3Smrg    if (d < 0) {
1003de2362d3Smrg	/* we missed the event, adjust target_msc, do the divisor magic */
10040d16fef4Smrg	CARD64 current_msc = last_vblank_seq;
10050d16fef4Smrg
1006de2362d3Smrg	delta_t = now - last_vblank_ust;
1007de2362d3Smrg	delta_seq = delta_t * nominal_frame_rate;
1008de2362d3Smrg	current_msc += delta_seq / 1000000;
1009de2362d3Smrg	current_msc &= 0xffffffff;
1010de2362d3Smrg	if (divisor == 0) {
1011de2362d3Smrg	    *target_msc = current_msc;
1012de2362d3Smrg	    d = 0;
1013de2362d3Smrg	} else {
1014de2362d3Smrg	    *target_msc = current_msc - (current_msc % divisor) + remainder;
1015de2362d3Smrg	    if ((current_msc % divisor) >= remainder)
1016de2362d3Smrg		*target_msc += divisor;
1017de2362d3Smrg	    *target_msc &= 0xffffffff;
10180d16fef4Smrg	    delta_seq = *target_msc - last_vblank_seq;
1019de2362d3Smrg	    delta_seq *= 1000000;
1020de2362d3Smrg	    target_time = last_vblank_ust;
1021de2362d3Smrg	    target_time += delta_seq / nominal_frame_rate;
1022de2362d3Smrg	    d = target_time - now;
1023de2362d3Smrg	}
1024de2362d3Smrg    }
1025de2362d3Smrg    /*
1026de2362d3Smrg     * convert delay to milliseconds and add margin to prevent the client
1027de2362d3Smrg     * from coming back early (due to timer granularity and rounding
1028de2362d3Smrg     * errors) and getting the same MSC it just got
1029de2362d3Smrg     */
1030de2362d3Smrg    d_ms = (CARD32)d / 1000;
1031de2362d3Smrg    if ((CARD32)d - d_ms * 1000 > 0)
1032de2362d3Smrg	d_ms += 2;
1033de2362d3Smrg    else
1034de2362d3Smrg	d_ms++;
1035de2362d3Smrg    return d_ms;
1036de2362d3Smrg}
1037de2362d3Smrg
1038de2362d3Smrg/*
10390d16fef4Smrg * Get current interpolated frame count and frame count timestamp, based on
10400d16fef4Smrg * drawable's crtc.
1041de2362d3Smrg */
1042de2362d3Smrgstatic int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
1043de2362d3Smrg{
1044de2362d3Smrg    xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE);
1045de2362d3Smrg
1046de2362d3Smrg    /* Drawable not displayed, make up a value */
1047de2362d3Smrg    if (crtc == NULL) {
1048de2362d3Smrg        *ust = 0;
1049de2362d3Smrg        *msc = 0;
1050de2362d3Smrg        return TRUE;
1051de2362d3Smrg    }
1052de2362d3Smrg
10530d16fef4Smrg    if (!radeon_dri2_get_crtc_msc(crtc, ust, msc))
10540d16fef4Smrg	return FALSE;
1055de2362d3Smrg
10560d16fef4Smrg    *msc += radeon_get_msc_delta(draw, crtc);
10570d16fef4Smrg    *msc &= 0xffffffff;
1058de2362d3Smrg    return TRUE;
1059de2362d3Smrg}
1060de2362d3Smrg
1061de2362d3Smrgstatic
1062de2362d3SmrgCARD32 radeon_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data)
1063de2362d3Smrg{
1064de2362d3Smrg    DRI2FrameEventPtr event_info = (DRI2FrameEventPtr)data;
10650d16fef4Smrg    xf86CrtcPtr crtc = event_info->crtc;
1066de2362d3Smrg    ScrnInfoPtr scrn;
1067de2362d3Smrg    RADEONInfoPtr info;
1068de2362d3Smrg    CARD64 drm_now;
1069de2362d3Smrg    int ret;
1070de2362d3Smrg    CARD64 delta_t, delta_seq, frame;
1071de2362d3Smrg    drmmode_crtc_private_ptr drmmode_crtc;
1072de2362d3Smrg
1073de2362d3Smrg    /*
1074de2362d3Smrg     * This is emulated event, so its time is current time, which we
1075de2362d3Smrg     * have to get in DRM-compatible form (which is a bit messy given
1076de2362d3Smrg     * the information that we have at this point). Can't use now argument
1077de2362d3Smrg     * because DRM event time may come from monotonic clock, while
1078de2362d3Smrg     * DIX timer facility uses real-time clock.
1079de2362d3Smrg     */
1080de2362d3Smrg    if (!event_info->crtc) {
1081de2362d3Smrg	ErrorF("%s no crtc\n", __func__);
10820d16fef4Smrg	if (event_info->drm_queue_seq)
10830d16fef4Smrg	    radeon_drm_abort_entry(event_info->drm_queue_seq);
10840d16fef4Smrg	else
10850d16fef4Smrg	    radeon_dri2_frame_event_abort(NULL, data);
1086de2362d3Smrg	return 0;
1087de2362d3Smrg    }
10880d16fef4Smrg
10890d16fef4Smrg    scrn = crtc->scrn;
1090de2362d3Smrg    info = RADEONPTR(scrn);
1091de2362d3Smrg    ret = drmmode_get_current_ust(info->dri2.drm_fd, &drm_now);
1092de2362d3Smrg    if (ret) {
1093de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1094de2362d3Smrg		   "%s cannot get current time\n", __func__);
10950d16fef4Smrg	if (event_info->drm_queue_seq)
10960d16fef4Smrg	    radeon_drm_queue_handler(info->dri2.drm_fd, 0, 0, 0,
10970d16fef4Smrg				     (void*)event_info->drm_queue_seq);
10980d16fef4Smrg	else
10990d16fef4Smrg	    radeon_dri2_frame_event_handler(crtc, 0, 0, data);
1100de2362d3Smrg	return 0;
1101de2362d3Smrg    }
1102de2362d3Smrg    /*
1103de2362d3Smrg     * calculate the frame number from current time
1104de2362d3Smrg     * that would come from CRTC if it were running
1105de2362d3Smrg     */
1106de2362d3Smrg    drmmode_crtc = event_info->crtc->driver_private;
1107de2362d3Smrg    delta_t = drm_now - (CARD64)drmmode_crtc->dpms_last_ust;
1108de2362d3Smrg    delta_seq = delta_t * drmmode_crtc->dpms_last_fps;
1109de2362d3Smrg    delta_seq /= 1000000;
1110de2362d3Smrg    frame = (CARD64)drmmode_crtc->dpms_last_seq + delta_seq;
11110d16fef4Smrg    if (event_info->drm_queue_seq)
11120d16fef4Smrg	radeon_drm_queue_handler(info->dri2.drm_fd, frame, drm_now / 1000000,
11130d16fef4Smrg				 drm_now % 1000000,
11140d16fef4Smrg				 (void*)event_info->drm_queue_seq);
11150d16fef4Smrg    else
11160d16fef4Smrg	radeon_dri2_frame_event_handler(crtc, frame, drm_now, data);
1117de2362d3Smrg    return 0;
1118de2362d3Smrg}
1119de2362d3Smrg
1120de2362d3Smrgstatic
11210d16fef4Smrgvoid radeon_dri2_schedule_event(CARD32 delay, DRI2FrameEventPtr event_info)
1122de2362d3Smrg{
11230d16fef4Smrg    event_info->timer = TimerSet(NULL, 0, delay, radeon_dri2_deferred_event,
11240d16fef4Smrg				 event_info);
1125de2362d3Smrg    if (delay == 0) {
1126de2362d3Smrg	CARD32 now = GetTimeInMillis();
11270d16fef4Smrg	radeon_dri2_deferred_event(event_info->timer, now, event_info);
1128de2362d3Smrg    }
1129de2362d3Smrg}
1130de2362d3Smrg
1131de2362d3Smrg/*
1132de2362d3Smrg * Request a DRM event when the requested conditions will be satisfied.
1133de2362d3Smrg *
1134de2362d3Smrg * We need to handle the event and ask the server to wake up the client when
1135de2362d3Smrg * we receive it.
1136de2362d3Smrg */
1137de2362d3Smrgstatic int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw,
1138de2362d3Smrg                                         CARD64 target_msc, CARD64 divisor,
1139de2362d3Smrg                                         CARD64 remainder)
1140de2362d3Smrg{
1141de2362d3Smrg    ScreenPtr screen = draw->pScreen;
1142de2362d3Smrg    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1143de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(scrn);
1144de2362d3Smrg    DRI2FrameEventPtr wait_info = NULL;
11450d16fef4Smrg    uintptr_t drm_queue_seq = 0;
1146de2362d3Smrg    xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE);
11470d16fef4Smrg    uint32_t msc_delta;
1148de2362d3Smrg    drmVBlank vbl;
1149de2362d3Smrg    int ret;
1150de2362d3Smrg    CARD64 current_msc;
1151de2362d3Smrg
1152de2362d3Smrg    /* Truncate to match kernel interfaces; means occasional overflow
1153de2362d3Smrg     * misses, but that's generally not a big deal */
1154de2362d3Smrg    target_msc &= 0xffffffff;
1155de2362d3Smrg    divisor &= 0xffffffff;
1156de2362d3Smrg    remainder &= 0xffffffff;
1157de2362d3Smrg
1158de2362d3Smrg    /* Drawable not visible, return immediately */
1159de2362d3Smrg    if (crtc == NULL)
1160de2362d3Smrg        goto out_complete;
1161de2362d3Smrg
11620d16fef4Smrg    msc_delta = radeon_get_msc_delta(draw, crtc);
11630d16fef4Smrg
1164de2362d3Smrg    wait_info = calloc(1, sizeof(DRI2FrameEventRec));
1165de2362d3Smrg    if (!wait_info)
1166de2362d3Smrg        goto out_complete;
1167de2362d3Smrg
1168de2362d3Smrg    wait_info->drawable_id = draw->id;
1169de2362d3Smrg    wait_info->client = client;
1170de2362d3Smrg    wait_info->type = DRI2_WAITMSC;
1171de2362d3Smrg    wait_info->crtc = crtc;
1172de2362d3Smrg
1173de2362d3Smrg    /*
1174de2362d3Smrg     * CRTC is in DPMS off state, calculate wait time from current time,
1175de2362d3Smrg     * target_msc and last vblank time/sequence when CRTC was turned off
1176de2362d3Smrg     */
1177de2362d3Smrg    if (!radeon_crtc_is_enabled(crtc)) {
1178de2362d3Smrg	CARD32 delay;
11790d16fef4Smrg	target_msc -= msc_delta;
1180de2362d3Smrg	delay = radeon_dri2_extrapolate_msc_delay(crtc, &target_msc,
1181de2362d3Smrg						  divisor, remainder);
1182de2362d3Smrg	radeon_dri2_schedule_event(delay, wait_info);
1183de2362d3Smrg	DRI2BlockClient(client, draw);
1184de2362d3Smrg	return TRUE;
1185de2362d3Smrg    }
1186de2362d3Smrg
1187de2362d3Smrg    /* Get current count */
1188de2362d3Smrg    vbl.request.type = DRM_VBLANK_RELATIVE;
1189de2362d3Smrg    vbl.request.type |= radeon_populate_vbl_request_type(crtc);
1190de2362d3Smrg    vbl.request.sequence = 0;
1191de2362d3Smrg    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
1192de2362d3Smrg    if (ret) {
1193de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1194de2362d3Smrg                "get vblank counter failed: %s\n", strerror(errno));
1195de2362d3Smrg        goto out_complete;
1196de2362d3Smrg    }
1197de2362d3Smrg
11980d16fef4Smrg    current_msc = vbl.reply.sequence + msc_delta;
1199de2362d3Smrg    current_msc &= 0xffffffff;
1200de2362d3Smrg
12010d16fef4Smrg    drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT,
12020d16fef4Smrg					   wait_info, radeon_dri2_frame_event_handler,
12030d16fef4Smrg					   radeon_dri2_frame_event_abort);
12040d16fef4Smrg    if (!drm_queue_seq) {
12050d16fef4Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
12060d16fef4Smrg		   "Allocating DRM queue event entry failed.\n");
12070d16fef4Smrg        goto out_complete;
12080d16fef4Smrg    }
12090d16fef4Smrg    wait_info->drm_queue_seq = drm_queue_seq;
12100d16fef4Smrg
1211de2362d3Smrg    /*
1212de2362d3Smrg     * If divisor is zero, or current_msc is smaller than target_msc,
1213de2362d3Smrg     * we just need to make sure target_msc passes  before waking up the
1214de2362d3Smrg     * client.
1215de2362d3Smrg     */
1216de2362d3Smrg    if (divisor == 0 || current_msc < target_msc) {
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 keeps the client from continually
1220de2362d3Smrg         * sending us MSC targets from the past by forcibly updating
1221de2362d3Smrg         * their count on this call.
1222de2362d3Smrg         */
1223de2362d3Smrg        if (current_msc >= target_msc)
1224de2362d3Smrg            target_msc = current_msc;
1225de2362d3Smrg        vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
1226de2362d3Smrg	vbl.request.type |= radeon_populate_vbl_request_type(crtc);
12270d16fef4Smrg        vbl.request.sequence = target_msc - msc_delta;
12280d16fef4Smrg        vbl.request.signal = drm_queue_seq;
1229de2362d3Smrg        ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
1230de2362d3Smrg        if (ret) {
1231de2362d3Smrg            xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1232de2362d3Smrg                    "get vblank counter failed: %s\n", strerror(errno));
1233de2362d3Smrg            goto out_complete;
1234de2362d3Smrg        }
1235de2362d3Smrg
1236de2362d3Smrg        DRI2BlockClient(client, draw);
1237de2362d3Smrg        return TRUE;
1238de2362d3Smrg    }
1239de2362d3Smrg
1240de2362d3Smrg    /*
1241de2362d3Smrg     * If we get here, target_msc has already passed or we don't have one,
1242de2362d3Smrg     * so we queue an event that will satisfy the divisor/remainder equation.
1243de2362d3Smrg     */
1244de2362d3Smrg    vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
1245de2362d3Smrg    vbl.request.type |= radeon_populate_vbl_request_type(crtc);
1246de2362d3Smrg
1247de2362d3Smrg    vbl.request.sequence = current_msc - (current_msc % divisor) +
12480d16fef4Smrg        remainder - msc_delta;
1249de2362d3Smrg
1250de2362d3Smrg    /*
1251de2362d3Smrg     * If calculated remainder is larger than requested remainder,
1252de2362d3Smrg     * it means we've passed the last point where
1253de2362d3Smrg     * seq % divisor == remainder, so we need to wait for the next time
1254de2362d3Smrg     * that will happen.
1255de2362d3Smrg     */
1256de2362d3Smrg    if ((current_msc % divisor) >= remainder)
1257de2362d3Smrg        vbl.request.sequence += divisor;
1258de2362d3Smrg
12590d16fef4Smrg    vbl.request.signal = drm_queue_seq;
1260de2362d3Smrg    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
1261de2362d3Smrg    if (ret) {
1262de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1263de2362d3Smrg                "get vblank counter failed: %s\n", strerror(errno));
1264de2362d3Smrg        goto out_complete;
1265de2362d3Smrg    }
1266de2362d3Smrg
1267de2362d3Smrg    DRI2BlockClient(client, draw);
1268de2362d3Smrg
1269de2362d3Smrg    return TRUE;
1270de2362d3Smrg
1271de2362d3Smrgout_complete:
12720d16fef4Smrg    if (wait_info)
12730d16fef4Smrg	radeon_dri2_deferred_event(NULL, 0, wait_info);
1274de2362d3Smrg    return TRUE;
1275de2362d3Smrg}
1276de2362d3Smrg
1277de2362d3Smrg/*
1278de2362d3Smrg * ScheduleSwap is responsible for requesting a DRM vblank event for the
1279de2362d3Smrg * appropriate frame.
1280de2362d3Smrg *
1281de2362d3Smrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
1282de2362d3Smrg * the vblank requested can simply be the last queued swap frame + the swap
1283de2362d3Smrg * interval for the drawable.
1284de2362d3Smrg *
1285de2362d3Smrg * In the case of a page flip, we request an event for the last queued swap
1286de2362d3Smrg * frame + swap interval - 1, since we'll need to queue the flip for the frame
1287de2362d3Smrg * immediately following the received event.
1288de2362d3Smrg *
1289de2362d3Smrg * The client will be blocked if it tries to perform further GL commands
1290de2362d3Smrg * after queueing a swap, though in the Intel case after queueing a flip, the
1291de2362d3Smrg * client is free to queue more commands; they'll block in the kernel if
1292de2362d3Smrg * they access buffers busy with the flip.
1293de2362d3Smrg *
1294de2362d3Smrg * When the swap is complete, the driver should call into the server so it
1295de2362d3Smrg * can send any swap complete events that have been requested.
1296de2362d3Smrg */
1297de2362d3Smrgstatic int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
1298de2362d3Smrg                                     DRI2BufferPtr front, DRI2BufferPtr back,
1299de2362d3Smrg                                     CARD64 *target_msc, CARD64 divisor,
1300de2362d3Smrg                                     CARD64 remainder, DRI2SwapEventPtr func,
1301de2362d3Smrg                                     void *data)
1302de2362d3Smrg{
1303de2362d3Smrg    ScreenPtr screen = draw->pScreen;
1304de2362d3Smrg    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1305de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(scrn);
1306de2362d3Smrg    xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE);
13070d16fef4Smrg    uint32_t msc_delta;
1308de2362d3Smrg    drmVBlank vbl;
1309de2362d3Smrg    int ret, flip = 0;
1310de2362d3Smrg    DRI2FrameEventPtr swap_info = NULL;
13110d16fef4Smrg    uintptr_t drm_queue_seq;
1312de2362d3Smrg    CARD64 current_msc;
1313de2362d3Smrg    BoxRec box;
1314de2362d3Smrg    RegionRec region;
1315de2362d3Smrg
1316de2362d3Smrg    /* Truncate to match kernel interfaces; means occasional overflow
1317de2362d3Smrg     * misses, but that's generally not a big deal */
1318de2362d3Smrg    *target_msc &= 0xffffffff;
1319de2362d3Smrg    divisor &= 0xffffffff;
1320de2362d3Smrg    remainder &= 0xffffffff;
1321de2362d3Smrg
1322de2362d3Smrg    /* radeon_dri2_frame_event_handler will get called some unknown time in the
1323de2362d3Smrg     * future with these buffers.  Take a reference to ensure that they won't
1324de2362d3Smrg     * get destroyed before then.
1325de2362d3Smrg     */
1326de2362d3Smrg    radeon_dri2_ref_buffer(front);
1327de2362d3Smrg    radeon_dri2_ref_buffer(back);
1328de2362d3Smrg
1329de2362d3Smrg    /* either off-screen or CRTC not usable... just complete the swap */
1330de2362d3Smrg    if (crtc == NULL)
1331de2362d3Smrg        goto blit_fallback;
1332de2362d3Smrg
13330d16fef4Smrg    msc_delta = radeon_get_msc_delta(draw, crtc);
13340d16fef4Smrg
1335de2362d3Smrg    swap_info = calloc(1, sizeof(DRI2FrameEventRec));
1336de2362d3Smrg    if (!swap_info)
1337de2362d3Smrg        goto blit_fallback;
1338de2362d3Smrg
13390d16fef4Smrg    swap_info->type = DRI2_SWAP;
1340de2362d3Smrg    swap_info->drawable_id = draw->id;
1341de2362d3Smrg    swap_info->client = client;
1342de2362d3Smrg    swap_info->event_complete = func;
1343de2362d3Smrg    swap_info->event_data = data;
1344de2362d3Smrg    swap_info->front = front;
1345de2362d3Smrg    swap_info->back = back;
1346de2362d3Smrg    swap_info->crtc = crtc;
13470d16fef4Smrg
13480d16fef4Smrg    drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT,
13490d16fef4Smrg					   swap_info, radeon_dri2_frame_event_handler,
13500d16fef4Smrg					   radeon_dri2_frame_event_abort);
13510d16fef4Smrg    if (!drm_queue_seq) {
1352de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
13530d16fef4Smrg		   "Allocating DRM queue entry failed.\n");
1354de2362d3Smrg        goto blit_fallback;
1355de2362d3Smrg    }
13560d16fef4Smrg    swap_info->drm_queue_seq = drm_queue_seq;
1357de2362d3Smrg
1358de2362d3Smrg    /*
1359de2362d3Smrg     * CRTC is in DPMS off state, fallback to blit, but calculate
1360de2362d3Smrg     * wait time from current time, target_msc and last vblank
1361de2362d3Smrg     * time/sequence when CRTC was turned off
1362de2362d3Smrg     */
1363de2362d3Smrg    if (!radeon_crtc_is_enabled(crtc)) {
1364de2362d3Smrg	CARD32 delay;
13650d16fef4Smrg	*target_msc -= msc_delta;
1366de2362d3Smrg	delay = radeon_dri2_extrapolate_msc_delay(crtc, target_msc,
1367de2362d3Smrg						  divisor, remainder);
13680d16fef4Smrg	*target_msc += msc_delta;
13690d16fef4Smrg	*target_msc &= 0xffffffff;
1370de2362d3Smrg	radeon_dri2_schedule_event(delay, swap_info);
1371de2362d3Smrg	return TRUE;
1372de2362d3Smrg    }
1373de2362d3Smrg
1374de2362d3Smrg    /* Get current count */
1375de2362d3Smrg    vbl.request.type = DRM_VBLANK_RELATIVE;
1376de2362d3Smrg    vbl.request.type |= radeon_populate_vbl_request_type(crtc);
1377de2362d3Smrg    vbl.request.sequence = 0;
1378de2362d3Smrg    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
1379de2362d3Smrg    if (ret) {
1380de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1381de2362d3Smrg                "first get vblank counter failed: %s\n",
1382de2362d3Smrg                strerror(errno));
13830d16fef4Smrg	goto blit_fallback;
1384de2362d3Smrg    }
1385de2362d3Smrg
13860d16fef4Smrg    current_msc = vbl.reply.sequence + msc_delta;
1387de2362d3Smrg    current_msc &= 0xffffffff;
1388de2362d3Smrg
1389de2362d3Smrg    /* Flips need to be submitted one frame before */
1390de2362d3Smrg    if (can_flip(scrn, draw, front, back)) {
13910d16fef4Smrg	swap_info->type = DRI2_FLIP;
1392de2362d3Smrg	flip = 1;
1393de2362d3Smrg    }
1394de2362d3Smrg
13950d16fef4Smrg    /* Correct target_msc by 'flip' if swap_info->type == DRI2_FLIP.
1396de2362d3Smrg     * Do it early, so handling of different timing constraints
1397de2362d3Smrg     * for divisor, remainder and msc vs. target_msc works.
1398de2362d3Smrg     */
1399de2362d3Smrg    if (*target_msc > 0)
1400de2362d3Smrg        *target_msc -= flip;
1401de2362d3Smrg
1402de2362d3Smrg    /*
1403de2362d3Smrg     * If divisor is zero, or current_msc is smaller than target_msc
1404de2362d3Smrg     * we just need to make sure target_msc passes before initiating
1405de2362d3Smrg     * the swap.
1406de2362d3Smrg     */
1407de2362d3Smrg    if (divisor == 0 || current_msc < *target_msc) {
1408de2362d3Smrg        vbl.request.type =  DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
1409de2362d3Smrg        /* If non-pageflipping, but blitting/exchanging, we need to use
1410de2362d3Smrg         * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
1411de2362d3Smrg         * on.
1412de2362d3Smrg         */
1413de2362d3Smrg        if (flip == 0)
1414de2362d3Smrg            vbl.request.type |= DRM_VBLANK_NEXTONMISS;
1415de2362d3Smrg	vbl.request.type |= radeon_populate_vbl_request_type(crtc);
1416de2362d3Smrg
1417de2362d3Smrg        /* If target_msc already reached or passed, set it to
1418de2362d3Smrg         * current_msc to ensure we return a reasonable value back
1419de2362d3Smrg         * to the caller. This makes swap_interval logic more robust.
1420de2362d3Smrg         */
1421de2362d3Smrg        if (current_msc >= *target_msc)
1422de2362d3Smrg            *target_msc = current_msc;
1423de2362d3Smrg
14240d16fef4Smrg        vbl.request.sequence = *target_msc - msc_delta;
14250d16fef4Smrg        vbl.request.signal = drm_queue_seq;
1426de2362d3Smrg        ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
1427de2362d3Smrg        if (ret) {
1428de2362d3Smrg            xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1429de2362d3Smrg                    "divisor 0 get vblank counter failed: %s\n",
1430de2362d3Smrg                    strerror(errno));
14310d16fef4Smrg	    goto blit_fallback;
1432de2362d3Smrg        }
1433de2362d3Smrg
14340d16fef4Smrg        *target_msc = vbl.reply.sequence + flip + msc_delta;
1435de2362d3Smrg        swap_info->frame = *target_msc;
1436de2362d3Smrg
1437de2362d3Smrg        return TRUE;
1438de2362d3Smrg    }
1439de2362d3Smrg
1440de2362d3Smrg    /*
1441de2362d3Smrg     * If we get here, target_msc has already passed or we don't have one,
1442de2362d3Smrg     * and we need to queue an event that will satisfy the divisor/remainder
1443de2362d3Smrg     * equation.
1444de2362d3Smrg     */
1445de2362d3Smrg    vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
1446de2362d3Smrg    if (flip == 0)
1447de2362d3Smrg        vbl.request.type |= DRM_VBLANK_NEXTONMISS;
1448de2362d3Smrg    vbl.request.type |= radeon_populate_vbl_request_type(crtc);
1449de2362d3Smrg
1450de2362d3Smrg    vbl.request.sequence = current_msc - (current_msc % divisor) +
14510d16fef4Smrg        remainder - msc_delta;
1452de2362d3Smrg
1453de2362d3Smrg    /*
1454de2362d3Smrg     * If the calculated deadline vbl.request.sequence is smaller than
1455de2362d3Smrg     * or equal to current_msc, it means we've passed the last point
1456de2362d3Smrg     * when effective onset frame seq could satisfy
1457de2362d3Smrg     * seq % divisor == remainder, so we need to wait for the next time
1458de2362d3Smrg     * this will happen.
1459de2362d3Smrg
1460de2362d3Smrg     * This comparison takes the 1 frame swap delay in pageflipping mode
1461de2362d3Smrg     * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
1462de2362d3Smrg     * if we are blitting/exchanging instead of flipping.
1463de2362d3Smrg     */
1464de2362d3Smrg    if (vbl.request.sequence <= current_msc)
1465de2362d3Smrg        vbl.request.sequence += divisor;
1466de2362d3Smrg
1467de2362d3Smrg    /* Account for 1 frame extra pageflip delay if flip > 0 */
1468de2362d3Smrg    vbl.request.sequence -= flip;
1469de2362d3Smrg
14700d16fef4Smrg    vbl.request.signal = drm_queue_seq;
1471de2362d3Smrg    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
1472de2362d3Smrg    if (ret) {
1473de2362d3Smrg        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1474de2362d3Smrg                "final get vblank counter failed: %s\n",
1475de2362d3Smrg                strerror(errno));
14760d16fef4Smrg	goto blit_fallback;
1477de2362d3Smrg    }
1478de2362d3Smrg
1479de2362d3Smrg    /* Adjust returned value for 1 fame pageflip offset of flip > 0 */
14800d16fef4Smrg    *target_msc = vbl.reply.sequence + flip + msc_delta;
14810d16fef4Smrg    *target_msc &= 0xffffffff;
1482de2362d3Smrg    swap_info->frame = *target_msc;
1483de2362d3Smrg
1484de2362d3Smrg    return TRUE;
1485de2362d3Smrg
1486de2362d3Smrgblit_fallback:
14870d16fef4Smrg    if (swap_info) {
14880d16fef4Smrg	swap_info->type = DRI2_SWAP;
14890d16fef4Smrg	radeon_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info);
14900d16fef4Smrg    } else {
14910d16fef4Smrg	box.x1 = 0;
14920d16fef4Smrg	box.y1 = 0;
14930d16fef4Smrg	box.x2 = draw->width;
14940d16fef4Smrg	box.y2 = draw->height;
14950d16fef4Smrg	REGION_INIT(pScreen, &region, &box, 0);
1496de2362d3Smrg
14970d16fef4Smrg	radeon_dri2_copy_region(draw, &region, front, back);
1498de2362d3Smrg
14990d16fef4Smrg	DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
1500de2362d3Smrg
15010d16fef4Smrg	radeon_dri2_unref_buffer(front);
15020d16fef4Smrg	radeon_dri2_unref_buffer(back);
15030d16fef4Smrg    }
1504de2362d3Smrg
1505de2362d3Smrg    *target_msc = 0; /* offscreen, so zero out target vblank count */
1506de2362d3Smrg    return TRUE;
1507de2362d3Smrg}
1508de2362d3Smrg
1509de2362d3Smrg
1510de2362d3SmrgBool
1511de2362d3Smrgradeon_dri2_screen_init(ScreenPtr pScreen)
1512de2362d3Smrg{
1513de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1514de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1515de2362d3Smrg    DRI2InfoRec dri2_info = { 0 };
1516de2362d3Smrg    const char *driverNames[2];
1517de2362d3Smrg    Bool scheduling_works = TRUE;
1518de2362d3Smrg
1519de2362d3Smrg    if (!info->dri2.available)
1520de2362d3Smrg        return FALSE;
1521de2362d3Smrg
1522de2362d3Smrg    info->dri2.device_name = drmGetDeviceNameFromFd(info->dri2.drm_fd);
1523de2362d3Smrg
1524de2362d3Smrg    if ( (info->ChipFamily >= CHIP_FAMILY_TAHITI) ) {
1525de2362d3Smrg        dri2_info.driverName = SI_DRIVER_NAME;
1526de2362d3Smrg    } else if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) {
1527de2362d3Smrg        dri2_info.driverName = R600_DRIVER_NAME;
1528de2362d3Smrg    } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) {
1529de2362d3Smrg        dri2_info.driverName = R300_DRIVER_NAME;
1530de2362d3Smrg    } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) {
1531de2362d3Smrg        dri2_info.driverName = R200_DRIVER_NAME;
1532de2362d3Smrg    } else {
1533de2362d3Smrg        dri2_info.driverName = RADEON_DRIVER_NAME;
1534de2362d3Smrg    }
1535de2362d3Smrg    dri2_info.fd = info->dri2.drm_fd;
1536de2362d3Smrg    dri2_info.deviceName = info->dri2.device_name;
1537de2362d3Smrg    dri2_info.version = DRI2INFOREC_VERSION;
1538de2362d3Smrg    dri2_info.CreateBuffer = radeon_dri2_create_buffer;
1539de2362d3Smrg    dri2_info.DestroyBuffer = radeon_dri2_destroy_buffer;
1540de2362d3Smrg    dri2_info.CopyRegion = radeon_dri2_copy_region;
1541de2362d3Smrg
1542de2362d3Smrg    if (info->dri2.pKernelDRMVersion->version_minor < 4) {
1543de2362d3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for "
1544de2362d3Smrg		   "sync extension\n");
1545de2362d3Smrg	scheduling_works = FALSE;
1546de2362d3Smrg    }
1547de2362d3Smrg
15480d16fef4Smrg    if (scheduling_works && info->drmmode.count_crtcs > 2) {
1549de2362d3Smrg#ifdef DRM_CAP_VBLANK_HIGH_CRTC
1550de2362d3Smrg	uint64_t cap_value;
1551de2362d3Smrg
1552de2362d3Smrg	if (drmGetCap(info->dri2.drm_fd, DRM_CAP_VBLANK_HIGH_CRTC, &cap_value)) {
1553de2362d3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel "
1554de2362d3Smrg		       "for VBLANKs on CRTC > 1\n");
1555de2362d3Smrg	    scheduling_works = FALSE;
1556de2362d3Smrg	} else if (!cap_value) {
1557de2362d3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Your kernel does not "
1558de2362d3Smrg		       "handle VBLANKs on CRTC > 1\n");
1559de2362d3Smrg	    scheduling_works = FALSE;
1560de2362d3Smrg	}
1561de2362d3Smrg#else
1562de2362d3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need to rebuild against a "
1563de2362d3Smrg		   "newer libdrm to handle VBLANKs on CRTC > 1\n");
1564de2362d3Smrg	scheduling_works = FALSE;
1565de2362d3Smrg#endif
1566de2362d3Smrg    }
1567de2362d3Smrg
1568de2362d3Smrg    if (scheduling_works) {
1569de2362d3Smrg        dri2_info.version = 4;
1570de2362d3Smrg        dri2_info.ScheduleSwap = radeon_dri2_schedule_swap;
1571de2362d3Smrg        dri2_info.GetMSC = radeon_dri2_get_msc;
1572de2362d3Smrg        dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc;
1573de2362d3Smrg        dri2_info.numDrivers = RADEON_ARRAY_SIZE(driverNames);
1574de2362d3Smrg        dri2_info.driverNames = driverNames;
15750d16fef4Smrg        driverNames[0] = dri2_info.driverName;
15760d16fef4Smrg
15770d16fef4Smrg        if (info->ChipFamily >= CHIP_FAMILY_R300)
15780d16fef4Smrg            driverNames[1] = driverNames[0];
15790d16fef4Smrg        else
15800d16fef4Smrg            driverNames[1] = NULL; /* no VDPAU support */
1581de2362d3Smrg
1582de2362d3Smrg	if (DRI2InfoCnt == 0) {
15830d16fef4Smrg	    if (!dixRegisterPrivateKey(dri2_window_private_key,
15840d16fef4Smrg				       PRIVATE_WINDOW,
15850d16fef4Smrg				       sizeof(struct dri2_window_priv))) {
15860d16fef4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
15870d16fef4Smrg			   "Failed to get DRI2 window private\n");
1588de2362d3Smrg		return FALSE;
1589de2362d3Smrg	    }
1590de2362d3Smrg
1591de2362d3Smrg	    AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0);
1592de2362d3Smrg	}
1593de2362d3Smrg
1594de2362d3Smrg	DRI2InfoCnt++;
1595de2362d3Smrg    }
1596de2362d3Smrg
1597de2362d3Smrg#if DRI2INFOREC_VERSION >= 9
1598de2362d3Smrg    dri2_info.version = 9;
1599de2362d3Smrg    dri2_info.CreateBuffer2 = radeon_dri2_create_buffer2;
1600de2362d3Smrg    dri2_info.DestroyBuffer2 = radeon_dri2_destroy_buffer2;
1601de2362d3Smrg    dri2_info.CopyRegion2 = radeon_dri2_copy_region2;
1602de2362d3Smrg#endif
1603de2362d3Smrg
1604de2362d3Smrg    info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info);
1605de2362d3Smrg    return info->dri2.enabled;
1606de2362d3Smrg}
1607de2362d3Smrg
1608de2362d3Smrgvoid radeon_dri2_close_screen(ScreenPtr pScreen)
1609de2362d3Smrg{
1610de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1611de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1612de2362d3Smrg
1613de2362d3Smrg    if (--DRI2InfoCnt == 0)
1614de2362d3Smrg    	DeleteCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0);
1615de2362d3Smrg
1616de2362d3Smrg    DRI2CloseScreen(pScreen);
1617de2362d3Smrg    drmFree(info->dri2.device_name);
1618de2362d3Smrg}
1619de2362d3Smrg
1620de2362d3Smrg#endif /* DRI2 */
1621de2362d3Smrg
1622