xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/drivers/modesetting/dri2.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright © 2013 Intel Corporation
3*4882a593Smuzhiyun  * Copyright © 2014 Broadcom
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
6*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
7*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
8*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
10*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * The above copyright notice and this permission notice (including the next
13*4882a593Smuzhiyun  * paragraph) shall be included in all copies or substantial portions of the
14*4882a593Smuzhiyun  * Software.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19*4882a593Smuzhiyun  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*4882a593Smuzhiyun  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*4882a593Smuzhiyun  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22*4882a593Smuzhiyun  * IN THE SOFTWARE.
23*4882a593Smuzhiyun  */
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /**
26*4882a593Smuzhiyun  * @file dri2.c
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  * Implements generic support for DRI2 on KMS, using glamor/exa pixmaps
29*4882a593Smuzhiyun  * for color buffer management (no support for other aux buffers), and
30*4882a593Smuzhiyun  * the DRM vblank ioctls.
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  * This doesn't implement pageflipping yet.
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
36*4882a593Smuzhiyun #include "dix-config.h"
37*4882a593Smuzhiyun #endif
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #include <time.h>
40*4882a593Smuzhiyun #include "list.h"
41*4882a593Smuzhiyun #include "xf86.h"
42*4882a593Smuzhiyun #include "driver.h"
43*4882a593Smuzhiyun #include "dri2.h"
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun enum ms_dri2_frame_event_type {
46*4882a593Smuzhiyun     MS_DRI2_QUEUE_SWAP,
47*4882a593Smuzhiyun     MS_DRI2_QUEUE_FLIP,
48*4882a593Smuzhiyun     MS_DRI2_WAIT_MSC,
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun typedef struct ms_dri2_frame_event {
52*4882a593Smuzhiyun     ScreenPtr screen;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun     DrawablePtr drawable;
55*4882a593Smuzhiyun     ClientPtr client;
56*4882a593Smuzhiyun     enum ms_dri2_frame_event_type type;
57*4882a593Smuzhiyun     int frame;
58*4882a593Smuzhiyun     xf86CrtcPtr crtc;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun     struct xorg_list drawable_resource, client_resource;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun     /* for swaps & flips only */
63*4882a593Smuzhiyun     DRI2SwapEventPtr event_complete;
64*4882a593Smuzhiyun     void *event_data;
65*4882a593Smuzhiyun     DRI2BufferPtr front;
66*4882a593Smuzhiyun     DRI2BufferPtr back;
67*4882a593Smuzhiyun } ms_dri2_frame_event_rec, *ms_dri2_frame_event_ptr;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun typedef struct {
70*4882a593Smuzhiyun     int refcnt;
71*4882a593Smuzhiyun     PixmapPtr pixmap;
72*4882a593Smuzhiyun } ms_dri2_buffer_private_rec, *ms_dri2_buffer_private_ptr;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun static DevPrivateKeyRec ms_dri2_client_key;
75*4882a593Smuzhiyun static RESTYPE frame_event_client_type, frame_event_drawable_type;
76*4882a593Smuzhiyun static int ms_dri2_server_generation;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun struct ms_dri2_resource {
79*4882a593Smuzhiyun     XID id;
80*4882a593Smuzhiyun     RESTYPE type;
81*4882a593Smuzhiyun     struct xorg_list list;
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun static struct ms_dri2_resource *
ms_get_resource(XID id,RESTYPE type)85*4882a593Smuzhiyun ms_get_resource(XID id, RESTYPE type)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun     struct ms_dri2_resource *resource;
88*4882a593Smuzhiyun     void *ptr;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun     ptr = NULL;
91*4882a593Smuzhiyun     dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess);
92*4882a593Smuzhiyun     if (ptr)
93*4882a593Smuzhiyun         return ptr;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun     resource = malloc(sizeof(*resource));
96*4882a593Smuzhiyun     if (resource == NULL)
97*4882a593Smuzhiyun         return NULL;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun     if (!AddResource(id, type, resource))
100*4882a593Smuzhiyun         return NULL;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun     resource->id = id;
103*4882a593Smuzhiyun     resource->type = type;
104*4882a593Smuzhiyun     xorg_list_init(&resource->list);
105*4882a593Smuzhiyun     return resource;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun static inline PixmapPtr
get_drawable_pixmap(DrawablePtr drawable)109*4882a593Smuzhiyun get_drawable_pixmap(DrawablePtr drawable)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun     ScreenPtr screen = drawable->pScreen;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun     if (drawable->type == DRAWABLE_PIXMAP)
114*4882a593Smuzhiyun         return (PixmapPtr) drawable;
115*4882a593Smuzhiyun     else
116*4882a593Smuzhiyun         return screen->GetWindowPixmap((WindowPtr) drawable);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun static DRI2Buffer2Ptr
ms_dri2_create_buffer2(ScreenPtr screen,DrawablePtr drawable,unsigned int attachment,unsigned int format)120*4882a593Smuzhiyun ms_dri2_create_buffer2(ScreenPtr screen, DrawablePtr drawable,
121*4882a593Smuzhiyun                        unsigned int attachment, unsigned int format)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
124*4882a593Smuzhiyun     DRI2Buffer2Ptr buffer;
125*4882a593Smuzhiyun     PixmapPtr pixmap;
126*4882a593Smuzhiyun     CARD32 size;
127*4882a593Smuzhiyun     CARD16 pitch;
128*4882a593Smuzhiyun     ms_dri2_buffer_private_ptr private;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun     buffer = calloc(1, sizeof *buffer);
131*4882a593Smuzhiyun     if (buffer == NULL)
132*4882a593Smuzhiyun         return NULL;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun     private = calloc(1, sizeof(*private));
135*4882a593Smuzhiyun     if (private == NULL) {
136*4882a593Smuzhiyun         free(buffer);
137*4882a593Smuzhiyun         return NULL;
138*4882a593Smuzhiyun     }
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun     pixmap = NULL;
141*4882a593Smuzhiyun     if (attachment == DRI2BufferFrontLeft) {
142*4882a593Smuzhiyun         pixmap = get_drawable_pixmap(drawable);
143*4882a593Smuzhiyun         if (pixmap && pixmap->drawable.pScreen != screen)
144*4882a593Smuzhiyun             pixmap = NULL;
145*4882a593Smuzhiyun         if (pixmap)
146*4882a593Smuzhiyun             pixmap->refcnt++;
147*4882a593Smuzhiyun     }
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun     if (pixmap == NULL) {
150*4882a593Smuzhiyun         int pixmap_width = drawable->width;
151*4882a593Smuzhiyun         int pixmap_height = drawable->height;
152*4882a593Smuzhiyun         int pixmap_cpp = (format != 0) ? format : drawable->depth;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun         /* Assume that non-color-buffers require special
155*4882a593Smuzhiyun          * device-specific handling.  Mesa currently makes no requests
156*4882a593Smuzhiyun          * for non-color aux buffers.
157*4882a593Smuzhiyun          */
158*4882a593Smuzhiyun         switch (attachment) {
159*4882a593Smuzhiyun         case DRI2BufferAccum:
160*4882a593Smuzhiyun         case DRI2BufferBackLeft:
161*4882a593Smuzhiyun         case DRI2BufferBackRight:
162*4882a593Smuzhiyun         case DRI2BufferFakeFrontLeft:
163*4882a593Smuzhiyun         case DRI2BufferFakeFrontRight:
164*4882a593Smuzhiyun         case DRI2BufferFrontLeft:
165*4882a593Smuzhiyun         case DRI2BufferFrontRight:
166*4882a593Smuzhiyun             break;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun         case DRI2BufferStencil:
169*4882a593Smuzhiyun         case DRI2BufferDepth:
170*4882a593Smuzhiyun         case DRI2BufferDepthStencil:
171*4882a593Smuzhiyun         case DRI2BufferHiz:
172*4882a593Smuzhiyun         default:
173*4882a593Smuzhiyun             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
174*4882a593Smuzhiyun                        "Request for DRI2 buffer attachment %d unsupported\n",
175*4882a593Smuzhiyun                        attachment);
176*4882a593Smuzhiyun             free(private);
177*4882a593Smuzhiyun             free(buffer);
178*4882a593Smuzhiyun             return NULL;
179*4882a593Smuzhiyun         }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun         pixmap = screen->CreatePixmap(screen,
182*4882a593Smuzhiyun                                       pixmap_width,
183*4882a593Smuzhiyun                                       pixmap_height,
184*4882a593Smuzhiyun                                       pixmap_cpp,
185*4882a593Smuzhiyun                                       0);
186*4882a593Smuzhiyun         if (pixmap == NULL) {
187*4882a593Smuzhiyun             free(private);
188*4882a593Smuzhiyun             free(buffer);
189*4882a593Smuzhiyun             return NULL;
190*4882a593Smuzhiyun         }
191*4882a593Smuzhiyun     }
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun     buffer->attachment = attachment;
194*4882a593Smuzhiyun     buffer->cpp = pixmap->drawable.bitsPerPixel / 8;
195*4882a593Smuzhiyun     buffer->format = format;
196*4882a593Smuzhiyun     /* The buffer's flags field is unused by the client drivers in
197*4882a593Smuzhiyun      * Mesa currently.
198*4882a593Smuzhiyun      */
199*4882a593Smuzhiyun     buffer->flags = 0;
200*4882a593Smuzhiyun     buffer->name = ms_name_from_pixmap(pixmap, &pitch, &size);
201*4882a593Smuzhiyun     buffer->pitch = pitch;
202*4882a593Smuzhiyun     if (buffer->name == -1) {
203*4882a593Smuzhiyun         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
204*4882a593Smuzhiyun                    "Failed to get DRI2 name for pixmap\n");
205*4882a593Smuzhiyun         screen->DestroyPixmap(pixmap);
206*4882a593Smuzhiyun         free(private);
207*4882a593Smuzhiyun         free(buffer);
208*4882a593Smuzhiyun         return NULL;
209*4882a593Smuzhiyun     }
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun     buffer->driverPrivate = private;
212*4882a593Smuzhiyun     private->refcnt = 1;
213*4882a593Smuzhiyun     private->pixmap = pixmap;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun     return buffer;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun static DRI2Buffer2Ptr
ms_dri2_create_buffer(DrawablePtr drawable,unsigned int attachment,unsigned int format)219*4882a593Smuzhiyun ms_dri2_create_buffer(DrawablePtr drawable, unsigned int attachment,
220*4882a593Smuzhiyun                       unsigned int format)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun     return ms_dri2_create_buffer2(drawable->pScreen, drawable, attachment,
223*4882a593Smuzhiyun                                   format);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun static void
ms_dri2_reference_buffer(DRI2Buffer2Ptr buffer)227*4882a593Smuzhiyun ms_dri2_reference_buffer(DRI2Buffer2Ptr buffer)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun     if (buffer) {
230*4882a593Smuzhiyun         ms_dri2_buffer_private_ptr private = buffer->driverPrivate;
231*4882a593Smuzhiyun         private->refcnt++;
232*4882a593Smuzhiyun     }
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
ms_dri2_destroy_buffer2(ScreenPtr unused,DrawablePtr unused2,DRI2Buffer2Ptr buffer)235*4882a593Smuzhiyun static void ms_dri2_destroy_buffer2(ScreenPtr unused, DrawablePtr unused2,
236*4882a593Smuzhiyun                                     DRI2Buffer2Ptr buffer)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun     if (!buffer)
239*4882a593Smuzhiyun         return;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun     if (buffer->driverPrivate) {
242*4882a593Smuzhiyun         ms_dri2_buffer_private_ptr private = buffer->driverPrivate;
243*4882a593Smuzhiyun         if (--private->refcnt == 0) {
244*4882a593Smuzhiyun             ScreenPtr screen = private->pixmap->drawable.pScreen;
245*4882a593Smuzhiyun             screen->DestroyPixmap(private->pixmap);
246*4882a593Smuzhiyun             free(private);
247*4882a593Smuzhiyun             free(buffer);
248*4882a593Smuzhiyun         }
249*4882a593Smuzhiyun     } else {
250*4882a593Smuzhiyun         free(buffer);
251*4882a593Smuzhiyun     }
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
ms_dri2_destroy_buffer(DrawablePtr drawable,DRI2Buffer2Ptr buffer)254*4882a593Smuzhiyun static void ms_dri2_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun     ms_dri2_destroy_buffer2(NULL, drawable, buffer);
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun static void
ms_dri2_copy_region2(ScreenPtr screen,DrawablePtr drawable,RegionPtr pRegion,DRI2BufferPtr destBuffer,DRI2BufferPtr sourceBuffer)260*4882a593Smuzhiyun ms_dri2_copy_region2(ScreenPtr screen, DrawablePtr drawable, RegionPtr pRegion,
261*4882a593Smuzhiyun                      DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun     ms_dri2_buffer_private_ptr src_priv = sourceBuffer->driverPrivate;
264*4882a593Smuzhiyun     ms_dri2_buffer_private_ptr dst_priv = destBuffer->driverPrivate;
265*4882a593Smuzhiyun     PixmapPtr src_pixmap = src_priv->pixmap;
266*4882a593Smuzhiyun     PixmapPtr dst_pixmap = dst_priv->pixmap;
267*4882a593Smuzhiyun     DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft)
268*4882a593Smuzhiyun         ? drawable : &src_pixmap->drawable;
269*4882a593Smuzhiyun     DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft)
270*4882a593Smuzhiyun         ? drawable : &dst_pixmap->drawable;
271*4882a593Smuzhiyun     int off_x = 0, off_y = 0;
272*4882a593Smuzhiyun     Bool translate = FALSE;
273*4882a593Smuzhiyun     RegionPtr pCopyClip;
274*4882a593Smuzhiyun     GCPtr gc;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun     if (destBuffer->attachment == DRI2BufferFrontLeft &&
277*4882a593Smuzhiyun              drawable->pScreen != screen) {
278*4882a593Smuzhiyun         dst = DRI2UpdatePrime(drawable, destBuffer);
279*4882a593Smuzhiyun         if (!dst)
280*4882a593Smuzhiyun             return;
281*4882a593Smuzhiyun         if (dst != drawable)
282*4882a593Smuzhiyun             translate = TRUE;
283*4882a593Smuzhiyun     }
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun     if (translate && drawable->type == DRAWABLE_WINDOW) {
286*4882a593Smuzhiyun #ifdef COMPOSITE
287*4882a593Smuzhiyun         PixmapPtr pixmap = get_drawable_pixmap(drawable);
288*4882a593Smuzhiyun         off_x = -pixmap->screen_x;
289*4882a593Smuzhiyun         off_y = -pixmap->screen_y;
290*4882a593Smuzhiyun #endif
291*4882a593Smuzhiyun         off_x += drawable->x;
292*4882a593Smuzhiyun         off_y += drawable->y;
293*4882a593Smuzhiyun     }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun     gc = GetScratchGC(dst->depth, screen);
296*4882a593Smuzhiyun     if (!gc)
297*4882a593Smuzhiyun         return;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun     pCopyClip = REGION_CREATE(screen, NULL, 0);
300*4882a593Smuzhiyun     REGION_COPY(screen, pCopyClip, pRegion);
301*4882a593Smuzhiyun     if (translate)
302*4882a593Smuzhiyun         REGION_TRANSLATE(screen, pCopyClip, off_x, off_y);
303*4882a593Smuzhiyun     (*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0);
304*4882a593Smuzhiyun     ValidateGC(dst, gc);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun     /* It's important that this copy gets submitted before the direct
307*4882a593Smuzhiyun      * rendering client submits rendering for the next frame, but we
308*4882a593Smuzhiyun      * don't actually need to submit right now.  The client will wait
309*4882a593Smuzhiyun      * for the DRI2CopyRegion reply or the swap buffer event before
310*4882a593Smuzhiyun      * rendering, and we'll hit the flush callback chain before those
311*4882a593Smuzhiyun      * messages are sent.  We submit our batch buffers from the flush
312*4882a593Smuzhiyun      * callback chain so we know that will happen before the client
313*4882a593Smuzhiyun      * tries to render again.
314*4882a593Smuzhiyun      */
315*4882a593Smuzhiyun     gc->ops->CopyArea(src, dst, gc,
316*4882a593Smuzhiyun                       0, 0,
317*4882a593Smuzhiyun                       drawable->width, drawable->height,
318*4882a593Smuzhiyun                       off_x, off_y);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun     FreeScratchGC(gc);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun static void
ms_dri2_copy_region(DrawablePtr drawable,RegionPtr pRegion,DRI2BufferPtr destBuffer,DRI2BufferPtr sourceBuffer)324*4882a593Smuzhiyun ms_dri2_copy_region(DrawablePtr drawable, RegionPtr pRegion,
325*4882a593Smuzhiyun                     DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun     ms_dri2_copy_region2(drawable->pScreen, drawable, pRegion, destBuffer,
328*4882a593Smuzhiyun                          sourceBuffer);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun static uint64_t
gettime_us(void)332*4882a593Smuzhiyun gettime_us(void)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun     struct timespec tv;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun     if (clock_gettime(CLOCK_MONOTONIC, &tv))
337*4882a593Smuzhiyun         return 0;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun     return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun /**
343*4882a593Smuzhiyun  * Get current frame count and frame count timestamp, based on drawable's
344*4882a593Smuzhiyun  * crtc.
345*4882a593Smuzhiyun  */
346*4882a593Smuzhiyun static int
ms_dri2_get_msc(DrawablePtr draw,CARD64 * ust,CARD64 * msc)347*4882a593Smuzhiyun ms_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun     int ret;
350*4882a593Smuzhiyun     xf86CrtcPtr crtc = ms_dri2_crtc_covering_drawable(draw);
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun     /* Drawable not displayed, make up a *monotonic* value */
353*4882a593Smuzhiyun     if (crtc == NULL) {
354*4882a593Smuzhiyun         *ust = gettime_us();
355*4882a593Smuzhiyun         *msc = 0;
356*4882a593Smuzhiyun         return TRUE;
357*4882a593Smuzhiyun     }
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun     ret = ms_get_crtc_ust_msc(crtc, ust, msc);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun     if (ret)
362*4882a593Smuzhiyun         return FALSE;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun     return TRUE;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun static XID
get_client_id(ClientPtr client)368*4882a593Smuzhiyun get_client_id(ClientPtr client)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun     XID *ptr = dixGetPrivateAddr(&client->devPrivates, &ms_dri2_client_key);
371*4882a593Smuzhiyun     if (*ptr == 0)
372*4882a593Smuzhiyun         *ptr = FakeClientID(client->index);
373*4882a593Smuzhiyun     return *ptr;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun /*
377*4882a593Smuzhiyun  * Hook this frame event into the server resource
378*4882a593Smuzhiyun  * database so we can clean it up if the drawable or
379*4882a593Smuzhiyun  * client exits while the swap is pending
380*4882a593Smuzhiyun  */
381*4882a593Smuzhiyun static Bool
ms_dri2_add_frame_event(ms_dri2_frame_event_ptr info)382*4882a593Smuzhiyun ms_dri2_add_frame_event(ms_dri2_frame_event_ptr info)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun     struct ms_dri2_resource *resource;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun     resource = ms_get_resource(get_client_id(info->client),
387*4882a593Smuzhiyun                                frame_event_client_type);
388*4882a593Smuzhiyun     if (resource == NULL)
389*4882a593Smuzhiyun         return FALSE;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun     xorg_list_add(&info->client_resource, &resource->list);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun     resource = ms_get_resource(info->drawable->id, frame_event_drawable_type);
394*4882a593Smuzhiyun     if (resource == NULL) {
395*4882a593Smuzhiyun         xorg_list_del(&info->client_resource);
396*4882a593Smuzhiyun         return FALSE;
397*4882a593Smuzhiyun     }
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun     xorg_list_add(&info->drawable_resource, &resource->list);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun     return TRUE;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun static void
ms_dri2_del_frame_event(ms_dri2_frame_event_rec * info)405*4882a593Smuzhiyun ms_dri2_del_frame_event(ms_dri2_frame_event_rec *info)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun     xorg_list_del(&info->client_resource);
408*4882a593Smuzhiyun     xorg_list_del(&info->drawable_resource);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun     if (info->front)
411*4882a593Smuzhiyun         ms_dri2_destroy_buffer(NULL, info->front);
412*4882a593Smuzhiyun     if (info->back)
413*4882a593Smuzhiyun         ms_dri2_destroy_buffer(NULL, info->back);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun     free(info);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun static void
ms_dri2_blit_swap(DrawablePtr drawable,DRI2BufferPtr dst,DRI2BufferPtr src)419*4882a593Smuzhiyun ms_dri2_blit_swap(DrawablePtr drawable,
420*4882a593Smuzhiyun                   DRI2BufferPtr dst,
421*4882a593Smuzhiyun                   DRI2BufferPtr src)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun     BoxRec box;
424*4882a593Smuzhiyun     RegionRec region;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun     box.x1 = 0;
427*4882a593Smuzhiyun     box.y1 = 0;
428*4882a593Smuzhiyun     box.x2 = drawable->width;
429*4882a593Smuzhiyun     box.y2 = drawable->height;
430*4882a593Smuzhiyun     REGION_INIT(pScreen, &region, &box, 0);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun     ms_dri2_copy_region(drawable, &region, dst, src);
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun struct ms_dri2_vblank_event {
436*4882a593Smuzhiyun     XID drawable_id;
437*4882a593Smuzhiyun     ClientPtr client;
438*4882a593Smuzhiyun     DRI2SwapEventPtr event_complete;
439*4882a593Smuzhiyun     void *event_data;
440*4882a593Smuzhiyun };
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun static void
ms_dri2_flip_abort(modesettingPtr ms,void * data)443*4882a593Smuzhiyun ms_dri2_flip_abort(modesettingPtr ms, void *data)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun     struct ms_present_vblank_event *event = data;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun     ms->drmmode.dri2_flipping = FALSE;
448*4882a593Smuzhiyun     free(event);
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun static void
ms_dri2_flip_handler(modesettingPtr ms,uint64_t msc,uint64_t ust,void * data)452*4882a593Smuzhiyun ms_dri2_flip_handler(modesettingPtr ms, uint64_t msc,
453*4882a593Smuzhiyun                      uint64_t ust, void *data)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun     struct ms_dri2_vblank_event *event = data;
456*4882a593Smuzhiyun     uint32_t frame = msc;
457*4882a593Smuzhiyun     uint32_t tv_sec = ust / 1000000;
458*4882a593Smuzhiyun     uint32_t tv_usec = ust % 1000000;
459*4882a593Smuzhiyun     DrawablePtr drawable;
460*4882a593Smuzhiyun     int status;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun     status = dixLookupDrawable(&drawable, event->drawable_id, serverClient,
463*4882a593Smuzhiyun                                M_ANY, DixWriteAccess);
464*4882a593Smuzhiyun     if (status == Success)
465*4882a593Smuzhiyun         DRI2SwapComplete(event->client, drawable, frame, tv_sec, tv_usec,
466*4882a593Smuzhiyun                          DRI2_FLIP_COMPLETE, event->event_complete,
467*4882a593Smuzhiyun                          event->event_data);
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun     ms->drmmode.dri2_flipping = FALSE;
470*4882a593Smuzhiyun     free(event);
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun static Bool
ms_dri2_schedule_flip(ms_dri2_frame_event_ptr info)474*4882a593Smuzhiyun ms_dri2_schedule_flip(ms_dri2_frame_event_ptr info)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun     DrawablePtr draw = info->drawable;
477*4882a593Smuzhiyun     ScreenPtr screen = draw->pScreen;
478*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
479*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
480*4882a593Smuzhiyun     ms_dri2_buffer_private_ptr back_priv = info->back->driverPrivate;
481*4882a593Smuzhiyun     struct ms_dri2_vblank_event *event;
482*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = info->crtc->driver_private;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun     event = calloc(1, sizeof(struct ms_dri2_vblank_event));
485*4882a593Smuzhiyun     if (!event)
486*4882a593Smuzhiyun         return FALSE;
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun     event->drawable_id = draw->id;
489*4882a593Smuzhiyun     event->client = info->client;
490*4882a593Smuzhiyun     event->event_complete = info->event_complete;
491*4882a593Smuzhiyun     event->event_data = info->event_data;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun     if (ms_do_pageflip(screen, back_priv->pixmap, event,
494*4882a593Smuzhiyun                        drmmode_crtc->vblank_pipe, FALSE,
495*4882a593Smuzhiyun                        ms_dri2_flip_handler,
496*4882a593Smuzhiyun                        ms_dri2_flip_abort)) {
497*4882a593Smuzhiyun         ms->drmmode.dri2_flipping = TRUE;
498*4882a593Smuzhiyun         drmmode_crtc->external_flipped = TRUE;
499*4882a593Smuzhiyun         return TRUE;
500*4882a593Smuzhiyun     }
501*4882a593Smuzhiyun     return FALSE;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun static Bool
update_front(DrawablePtr draw,DRI2BufferPtr front)505*4882a593Smuzhiyun update_front(DrawablePtr draw, DRI2BufferPtr front)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun     ScreenPtr screen = draw->pScreen;
508*4882a593Smuzhiyun     PixmapPtr pixmap = get_drawable_pixmap(draw);
509*4882a593Smuzhiyun     ms_dri2_buffer_private_ptr priv = front->driverPrivate;
510*4882a593Smuzhiyun     CARD32 size;
511*4882a593Smuzhiyun     CARD16 pitch;
512*4882a593Smuzhiyun     int name;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun     name = ms_name_from_pixmap(pixmap, &pitch, &size);
515*4882a593Smuzhiyun     if (name < 0)
516*4882a593Smuzhiyun         return FALSE;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun     front->name = name;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun     (*screen->DestroyPixmap) (priv->pixmap);
521*4882a593Smuzhiyun     front->pitch = pixmap->devKind;
522*4882a593Smuzhiyun     front->cpp = pixmap->drawable.bitsPerPixel / 8;
523*4882a593Smuzhiyun     priv->pixmap = pixmap;
524*4882a593Smuzhiyun     pixmap->refcnt++;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun     return TRUE;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun static Bool
can_exchange(ScrnInfoPtr scrn,DrawablePtr draw,DRI2BufferPtr front,DRI2BufferPtr back)530*4882a593Smuzhiyun can_exchange(ScrnInfoPtr scrn, DrawablePtr draw,
531*4882a593Smuzhiyun 	     DRI2BufferPtr front, DRI2BufferPtr back)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun     ms_dri2_buffer_private_ptr front_priv = front->driverPrivate;
534*4882a593Smuzhiyun     ms_dri2_buffer_private_ptr back_priv = back->driverPrivate;
535*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
536*4882a593Smuzhiyun     PixmapPtr front_pixmap;
537*4882a593Smuzhiyun     PixmapPtr back_pixmap = back_priv->pixmap;
538*4882a593Smuzhiyun     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
539*4882a593Smuzhiyun     int num_crtcs_on = 0;
540*4882a593Smuzhiyun     int i;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun     for (i = 0; i < config->num_crtc; i++) {
543*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = config->crtc[i]->driver_private;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun         /* Don't do pageflipping if CRTCs are rotated. */
546*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
547*4882a593Smuzhiyun         if (drmmode_crtc->rotate_bo.gbm)
548*4882a593Smuzhiyun             return FALSE;
549*4882a593Smuzhiyun #endif
550*4882a593Smuzhiyun         if (drmmode_crtc->rotate_bo.dumb)
551*4882a593Smuzhiyun             return FALSE;
552*4882a593Smuzhiyun         if (config->crtc[i]->driverIsPerformingTransform &
553*4882a593Smuzhiyun             XF86DriverTransformOutput)
554*4882a593Smuzhiyun             return FALSE;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun         if (ms_crtc_on(config->crtc[i]))
557*4882a593Smuzhiyun             num_crtcs_on++;
558*4882a593Smuzhiyun     }
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun     /* We can't do pageflipping if all the CRTCs are off. */
561*4882a593Smuzhiyun     if (num_crtcs_on == 0)
562*4882a593Smuzhiyun         return FALSE;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun     if (!update_front(draw, front))
565*4882a593Smuzhiyun         return FALSE;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun     front_pixmap = front_priv->pixmap;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun     if (front_pixmap->drawable.width != back_pixmap->drawable.width)
570*4882a593Smuzhiyun         return FALSE;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun     if (front_pixmap->drawable.height != back_pixmap->drawable.height)
573*4882a593Smuzhiyun         return FALSE;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun     if (front_pixmap->drawable.bitsPerPixel !=
576*4882a593Smuzhiyun         back_pixmap->drawable.bitsPerPixel)
577*4882a593Smuzhiyun         return FALSE;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun     if (front_pixmap->devKind != back_pixmap->devKind)
580*4882a593Smuzhiyun         return FALSE;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun     if (!ms->drmmode.glamor && !ms->drmmode.exa)
583*4882a593Smuzhiyun         return FALSE;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun     return TRUE;
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun static Bool
can_flip(ScrnInfoPtr scrn,DrawablePtr draw,DRI2BufferPtr front,DRI2BufferPtr back)589*4882a593Smuzhiyun can_flip(ScrnInfoPtr scrn, DrawablePtr draw,
590*4882a593Smuzhiyun 	 DRI2BufferPtr front, DRI2BufferPtr back)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun     return draw->type == DRAWABLE_WINDOW &&
595*4882a593Smuzhiyun         ms->drmmode.pageflip &&
596*4882a593Smuzhiyun         !ms->drmmode.sprites_visible &&
597*4882a593Smuzhiyun         !ms->drmmode.present_flipping &&
598*4882a593Smuzhiyun         scrn->vtSema &&
599*4882a593Smuzhiyun         DRI2CanFlip(draw) && can_exchange(scrn, draw, front, back);
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun static void
ms_dri2_exchange_buffers(DrawablePtr draw,DRI2BufferPtr front,DRI2BufferPtr back)603*4882a593Smuzhiyun ms_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front,
604*4882a593Smuzhiyun                          DRI2BufferPtr back)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun     ms_dri2_buffer_private_ptr front_priv = front->driverPrivate;
607*4882a593Smuzhiyun     ms_dri2_buffer_private_ptr back_priv = back->driverPrivate;
608*4882a593Smuzhiyun     ScreenPtr screen = draw->pScreen;
609*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
610*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
611*4882a593Smuzhiyun     msPixmapPrivPtr front_pix = msGetPixmapPriv(&ms->drmmode, front_priv->pixmap);
612*4882a593Smuzhiyun     msPixmapPrivPtr back_pix = msGetPixmapPriv(&ms->drmmode, back_priv->pixmap);
613*4882a593Smuzhiyun     msPixmapPrivRec tmp_pix;
614*4882a593Smuzhiyun     RegionRec region;
615*4882a593Smuzhiyun     int tmp;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun     /* Swap BO names so DRI works */
618*4882a593Smuzhiyun     tmp = front->name;
619*4882a593Smuzhiyun     front->name = back->name;
620*4882a593Smuzhiyun     back->name = tmp;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun     /* Swap pixmap privates */
623*4882a593Smuzhiyun     tmp_pix = *front_pix;
624*4882a593Smuzhiyun     *front_pix = *back_pix;
625*4882a593Smuzhiyun     *back_pix = tmp_pix;
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun     /* Post damage on the front buffer so that listeners, such
628*4882a593Smuzhiyun      * as DisplayLink know take a copy and shove it over the USB.
629*4882a593Smuzhiyun      */
630*4882a593Smuzhiyun     region.extents.x1 = region.extents.y1 = 0;
631*4882a593Smuzhiyun     region.extents.x2 = front_priv->pixmap->drawable.width;
632*4882a593Smuzhiyun     region.extents.y2 = front_priv->pixmap->drawable.height;
633*4882a593Smuzhiyun     region.data = NULL;
634*4882a593Smuzhiyun     DamageRegionAppend(&front_priv->pixmap->drawable, &region);
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun     ms_exchange_buffers(front_priv->pixmap, back_priv->pixmap);
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun     DamageRegionProcessPending(&front_priv->pixmap->drawable);
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun static void
ms_dri2_frame_event_handler(uint64_t msc,uint64_t usec,void * data)642*4882a593Smuzhiyun ms_dri2_frame_event_handler(uint64_t msc,
643*4882a593Smuzhiyun                             uint64_t usec,
644*4882a593Smuzhiyun                             void *data)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun     ms_dri2_frame_event_ptr frame_info = data;
647*4882a593Smuzhiyun     DrawablePtr drawable = frame_info->drawable;
648*4882a593Smuzhiyun     ScreenPtr screen = frame_info->screen;
649*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
650*4882a593Smuzhiyun     uint32_t tv_sec = usec / 1000000;
651*4882a593Smuzhiyun     uint32_t tv_usec = usec % 1000000;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun     if (!drawable) {
654*4882a593Smuzhiyun         ms_dri2_del_frame_event(frame_info);
655*4882a593Smuzhiyun         return;
656*4882a593Smuzhiyun     }
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun     switch (frame_info->type) {
659*4882a593Smuzhiyun     case MS_DRI2_QUEUE_FLIP:
660*4882a593Smuzhiyun         if (can_flip(scrn, drawable, frame_info->front, frame_info->back) &&
661*4882a593Smuzhiyun             ms_dri2_schedule_flip(frame_info)) {
662*4882a593Smuzhiyun             ms_dri2_exchange_buffers(drawable, frame_info->front, frame_info->back);
663*4882a593Smuzhiyun             break;
664*4882a593Smuzhiyun         }
665*4882a593Smuzhiyun         /* else fall through to blit */
666*4882a593Smuzhiyun     case MS_DRI2_QUEUE_SWAP:
667*4882a593Smuzhiyun         ms_dri2_blit_swap(drawable, frame_info->front, frame_info->back);
668*4882a593Smuzhiyun         DRI2SwapComplete(frame_info->client, drawable, msc, tv_sec, tv_usec,
669*4882a593Smuzhiyun                          DRI2_BLIT_COMPLETE,
670*4882a593Smuzhiyun                          frame_info->client ? frame_info->event_complete : NULL,
671*4882a593Smuzhiyun                          frame_info->event_data);
672*4882a593Smuzhiyun         break;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun     case MS_DRI2_WAIT_MSC:
675*4882a593Smuzhiyun         if (frame_info->client)
676*4882a593Smuzhiyun             DRI2WaitMSCComplete(frame_info->client, drawable,
677*4882a593Smuzhiyun                                 msc, tv_sec, tv_usec);
678*4882a593Smuzhiyun         break;
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun     default:
681*4882a593Smuzhiyun         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
682*4882a593Smuzhiyun                    "%s: unknown vblank event (type %d) received\n", __func__,
683*4882a593Smuzhiyun                    frame_info->type);
684*4882a593Smuzhiyun         break;
685*4882a593Smuzhiyun     }
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun     ms_dri2_del_frame_event(frame_info);
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun static void
ms_dri2_frame_event_abort(void * data)691*4882a593Smuzhiyun ms_dri2_frame_event_abort(void *data)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun     ms_dri2_frame_event_ptr frame_info = data;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun     ms_dri2_del_frame_event(frame_info);
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun /**
699*4882a593Smuzhiyun  * Request a DRM event when the requested conditions will be satisfied.
700*4882a593Smuzhiyun  *
701*4882a593Smuzhiyun  * We need to handle the event and ask the server to wake up the client when
702*4882a593Smuzhiyun  * we receive it.
703*4882a593Smuzhiyun  */
704*4882a593Smuzhiyun static int
ms_dri2_schedule_wait_msc(ClientPtr client,DrawablePtr draw,CARD64 target_msc,CARD64 divisor,CARD64 remainder)705*4882a593Smuzhiyun ms_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
706*4882a593Smuzhiyun                           CARD64 divisor, CARD64 remainder)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun     ScreenPtr screen = draw->pScreen;
709*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
710*4882a593Smuzhiyun     ms_dri2_frame_event_ptr wait_info;
711*4882a593Smuzhiyun     int ret;
712*4882a593Smuzhiyun     xf86CrtcPtr crtc = ms_dri2_crtc_covering_drawable(draw);
713*4882a593Smuzhiyun     CARD64 current_msc, current_ust, request_msc;
714*4882a593Smuzhiyun     uint32_t seq;
715*4882a593Smuzhiyun     uint64_t queued_msc;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun     /* Drawable not visible, return immediately */
718*4882a593Smuzhiyun     if (!crtc)
719*4882a593Smuzhiyun         goto out_complete;
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun     wait_info = calloc(1, sizeof(*wait_info));
722*4882a593Smuzhiyun     if (!wait_info)
723*4882a593Smuzhiyun         goto out_complete;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun     wait_info->screen = screen;
726*4882a593Smuzhiyun     wait_info->drawable = draw;
727*4882a593Smuzhiyun     wait_info->client = client;
728*4882a593Smuzhiyun     wait_info->type = MS_DRI2_WAIT_MSC;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun     if (!ms_dri2_add_frame_event(wait_info)) {
731*4882a593Smuzhiyun         free(wait_info);
732*4882a593Smuzhiyun         wait_info = NULL;
733*4882a593Smuzhiyun         goto out_complete;
734*4882a593Smuzhiyun     }
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun     /* Get current count */
737*4882a593Smuzhiyun     ret = ms_get_crtc_ust_msc(crtc, &current_ust, &current_msc);
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun     /*
740*4882a593Smuzhiyun      * If divisor is zero, or current_msc is smaller than target_msc,
741*4882a593Smuzhiyun      * we just need to make sure target_msc passes  before waking up the
742*4882a593Smuzhiyun      * client.
743*4882a593Smuzhiyun      */
744*4882a593Smuzhiyun     if (divisor == 0 || current_msc < target_msc) {
745*4882a593Smuzhiyun         /* If target_msc already reached or passed, set it to
746*4882a593Smuzhiyun          * current_msc to ensure we return a reasonable value back
747*4882a593Smuzhiyun          * to the caller. This keeps the client from continually
748*4882a593Smuzhiyun          * sending us MSC targets from the past by forcibly updating
749*4882a593Smuzhiyun          * their count on this call.
750*4882a593Smuzhiyun          */
751*4882a593Smuzhiyun         seq = ms_drm_queue_alloc(crtc, wait_info,
752*4882a593Smuzhiyun                                  ms_dri2_frame_event_handler,
753*4882a593Smuzhiyun                                  ms_dri2_frame_event_abort);
754*4882a593Smuzhiyun         if (!seq)
755*4882a593Smuzhiyun             goto out_free;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun         if (current_msc >= target_msc)
758*4882a593Smuzhiyun             target_msc = current_msc;
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun         ret = ms_queue_vblank(crtc, MS_QUEUE_ABSOLUTE, target_msc, &queued_msc, seq);
761*4882a593Smuzhiyun         if (!ret) {
762*4882a593Smuzhiyun             static int limit = 5;
763*4882a593Smuzhiyun             if (limit) {
764*4882a593Smuzhiyun                 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
765*4882a593Smuzhiyun                            "%s:%d get vblank counter failed: %s\n",
766*4882a593Smuzhiyun                            __FUNCTION__, __LINE__,
767*4882a593Smuzhiyun                            strerror(errno));
768*4882a593Smuzhiyun                 limit--;
769*4882a593Smuzhiyun             }
770*4882a593Smuzhiyun             goto out_free;
771*4882a593Smuzhiyun         }
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun         wait_info->frame = queued_msc;
774*4882a593Smuzhiyun         DRI2BlockClient(client, draw);
775*4882a593Smuzhiyun         return TRUE;
776*4882a593Smuzhiyun     }
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun     /*
779*4882a593Smuzhiyun      * If we get here, target_msc has already passed or we don't have one,
780*4882a593Smuzhiyun      * so we queue an event that will satisfy the divisor/remainder equation.
781*4882a593Smuzhiyun      */
782*4882a593Smuzhiyun     request_msc = current_msc - (current_msc % divisor) +
783*4882a593Smuzhiyun         remainder;
784*4882a593Smuzhiyun     /*
785*4882a593Smuzhiyun      * If calculated remainder is larger than requested remainder,
786*4882a593Smuzhiyun      * it means we've passed the last point where
787*4882a593Smuzhiyun      * seq % divisor == remainder, so we need to wait for the next time
788*4882a593Smuzhiyun      * that will happen.
789*4882a593Smuzhiyun      */
790*4882a593Smuzhiyun     if ((current_msc % divisor) >= remainder)
791*4882a593Smuzhiyun         request_msc += divisor;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun     seq = ms_drm_queue_alloc(crtc, wait_info,
794*4882a593Smuzhiyun                              ms_dri2_frame_event_handler,
795*4882a593Smuzhiyun                              ms_dri2_frame_event_abort);
796*4882a593Smuzhiyun     if (!seq)
797*4882a593Smuzhiyun         goto out_free;
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun     if (!ms_queue_vblank(crtc, MS_QUEUE_ABSOLUTE, request_msc, &queued_msc, seq)) {
800*4882a593Smuzhiyun         static int limit = 5;
801*4882a593Smuzhiyun         if (limit) {
802*4882a593Smuzhiyun             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
803*4882a593Smuzhiyun                        "%s:%d get vblank counter failed: %s\n",
804*4882a593Smuzhiyun                        __FUNCTION__, __LINE__,
805*4882a593Smuzhiyun                        strerror(errno));
806*4882a593Smuzhiyun             limit--;
807*4882a593Smuzhiyun         }
808*4882a593Smuzhiyun         goto out_free;
809*4882a593Smuzhiyun     }
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun     wait_info->frame = queued_msc;
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun     DRI2BlockClient(client, draw);
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun     return TRUE;
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun  out_free:
818*4882a593Smuzhiyun     ms_dri2_del_frame_event(wait_info);
819*4882a593Smuzhiyun  out_complete:
820*4882a593Smuzhiyun     DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
821*4882a593Smuzhiyun     return TRUE;
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun /**
825*4882a593Smuzhiyun  * ScheduleSwap is responsible for requesting a DRM vblank event for
826*4882a593Smuzhiyun  * the appropriate frame, or executing the swap immediately if it
827*4882a593Smuzhiyun  * doesn't need to wait.
828*4882a593Smuzhiyun  *
829*4882a593Smuzhiyun  * When the swap is complete, the driver should call into the server so it
830*4882a593Smuzhiyun  * can send any swap complete events that have been requested.
831*4882a593Smuzhiyun  */
832*4882a593Smuzhiyun static int
ms_dri2_schedule_swap(ClientPtr client,DrawablePtr draw,DRI2BufferPtr front,DRI2BufferPtr back,CARD64 * target_msc,CARD64 divisor,CARD64 remainder,DRI2SwapEventPtr func,void * data)833*4882a593Smuzhiyun ms_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
834*4882a593Smuzhiyun                       DRI2BufferPtr front, DRI2BufferPtr back,
835*4882a593Smuzhiyun                       CARD64 *target_msc, CARD64 divisor,
836*4882a593Smuzhiyun                       CARD64 remainder, DRI2SwapEventPtr func, void *data)
837*4882a593Smuzhiyun {
838*4882a593Smuzhiyun     ScreenPtr screen = draw->pScreen;
839*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
840*4882a593Smuzhiyun     int ret, flip = 0;
841*4882a593Smuzhiyun     xf86CrtcPtr crtc = ms_dri2_crtc_covering_drawable(draw);
842*4882a593Smuzhiyun     ms_dri2_frame_event_ptr frame_info = NULL;
843*4882a593Smuzhiyun     uint64_t current_msc, current_ust;
844*4882a593Smuzhiyun     uint64_t request_msc;
845*4882a593Smuzhiyun     uint32_t seq;
846*4882a593Smuzhiyun     ms_queue_flag ms_flag = MS_QUEUE_ABSOLUTE;
847*4882a593Smuzhiyun     uint64_t queued_msc;
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun     /* Drawable not displayed... just complete the swap */
850*4882a593Smuzhiyun     if (!crtc)
851*4882a593Smuzhiyun         goto blit_fallback;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun     frame_info = calloc(1, sizeof(*frame_info));
854*4882a593Smuzhiyun     if (!frame_info)
855*4882a593Smuzhiyun         goto blit_fallback;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun     frame_info->screen = screen;
858*4882a593Smuzhiyun     frame_info->drawable = draw;
859*4882a593Smuzhiyun     frame_info->client = client;
860*4882a593Smuzhiyun     frame_info->event_complete = func;
861*4882a593Smuzhiyun     frame_info->event_data = data;
862*4882a593Smuzhiyun     frame_info->front = front;
863*4882a593Smuzhiyun     frame_info->back = back;
864*4882a593Smuzhiyun     frame_info->crtc = crtc;
865*4882a593Smuzhiyun     frame_info->type = MS_DRI2_QUEUE_SWAP;
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun     if (!ms_dri2_add_frame_event(frame_info)) {
868*4882a593Smuzhiyun         free(frame_info);
869*4882a593Smuzhiyun         frame_info = NULL;
870*4882a593Smuzhiyun         goto blit_fallback;
871*4882a593Smuzhiyun     }
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun     ms_dri2_reference_buffer(front);
874*4882a593Smuzhiyun     ms_dri2_reference_buffer(back);
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun     ret = ms_get_crtc_ust_msc(crtc, &current_ust, &current_msc);
877*4882a593Smuzhiyun     if (ret != Success)
878*4882a593Smuzhiyun         goto blit_fallback;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun     /* Flips need to be submitted one frame before */
881*4882a593Smuzhiyun     if (can_flip(scrn, draw, front, back)) {
882*4882a593Smuzhiyun         frame_info->type = MS_DRI2_QUEUE_FLIP;
883*4882a593Smuzhiyun         flip = 1;
884*4882a593Smuzhiyun     }
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun     /* Correct target_msc by 'flip' if frame_info->type == MS_DRI2_QUEUE_FLIP.
887*4882a593Smuzhiyun      * Do it early, so handling of different timing constraints
888*4882a593Smuzhiyun      * for divisor, remainder and msc vs. target_msc works.
889*4882a593Smuzhiyun      */
890*4882a593Smuzhiyun     if (*target_msc > 0)
891*4882a593Smuzhiyun         *target_msc -= flip;
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun     /* If non-pageflipping, but blitting/exchanging, we need to use
894*4882a593Smuzhiyun      * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
895*4882a593Smuzhiyun      * on.
896*4882a593Smuzhiyun      */
897*4882a593Smuzhiyun     if (flip == 0)
898*4882a593Smuzhiyun         ms_flag |= MS_QUEUE_NEXT_ON_MISS;
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun     /*
901*4882a593Smuzhiyun      * If divisor is zero, or current_msc is smaller than target_msc
902*4882a593Smuzhiyun      * we just need to make sure target_msc passes before initiating
903*4882a593Smuzhiyun      * the swap.
904*4882a593Smuzhiyun      */
905*4882a593Smuzhiyun     if (divisor == 0 || current_msc < *target_msc) {
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun         /* If target_msc already reached or passed, set it to
908*4882a593Smuzhiyun          * current_msc to ensure we return a reasonable value back
909*4882a593Smuzhiyun          * to the caller. This makes swap_interval logic more robust.
910*4882a593Smuzhiyun          */
911*4882a593Smuzhiyun         if (current_msc >= *target_msc)
912*4882a593Smuzhiyun             *target_msc = current_msc;
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun         seq = ms_drm_queue_alloc(crtc, frame_info,
915*4882a593Smuzhiyun                                  ms_dri2_frame_event_handler,
916*4882a593Smuzhiyun                                  ms_dri2_frame_event_abort);
917*4882a593Smuzhiyun         if (!seq)
918*4882a593Smuzhiyun             goto blit_fallback;
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun         if (!ms_queue_vblank(crtc, ms_flag, *target_msc, &queued_msc, seq)) {
921*4882a593Smuzhiyun             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
922*4882a593Smuzhiyun                        "divisor 0 get vblank counter failed: %s\n",
923*4882a593Smuzhiyun                        strerror(errno));
924*4882a593Smuzhiyun             goto blit_fallback;
925*4882a593Smuzhiyun         }
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun         *target_msc = queued_msc + flip;
928*4882a593Smuzhiyun         frame_info->frame = *target_msc;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun         return TRUE;
931*4882a593Smuzhiyun     }
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun     /*
934*4882a593Smuzhiyun      * If we get here, target_msc has already passed or we don't have one,
935*4882a593Smuzhiyun      * and we need to queue an event that will satisfy the divisor/remainder
936*4882a593Smuzhiyun      * equation.
937*4882a593Smuzhiyun      */
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun     request_msc = current_msc - (current_msc % divisor) +
940*4882a593Smuzhiyun         remainder;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun     /*
943*4882a593Smuzhiyun      * If the calculated deadline vbl.request.sequence is smaller than
944*4882a593Smuzhiyun      * or equal to current_msc, it means we've passed the last point
945*4882a593Smuzhiyun      * when effective onset frame seq could satisfy
946*4882a593Smuzhiyun      * seq % divisor == remainder, so we need to wait for the next time
947*4882a593Smuzhiyun      * this will happen.
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun      * This comparison takes the DRM_VBLANK_NEXTONMISS delay into account.
950*4882a593Smuzhiyun      */
951*4882a593Smuzhiyun     if (request_msc <= current_msc)
952*4882a593Smuzhiyun         request_msc += divisor;
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun     seq = ms_drm_queue_alloc(crtc, frame_info,
955*4882a593Smuzhiyun                              ms_dri2_frame_event_handler,
956*4882a593Smuzhiyun                              ms_dri2_frame_event_abort);
957*4882a593Smuzhiyun     if (!seq)
958*4882a593Smuzhiyun         goto blit_fallback;
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun     /* Account for 1 frame extra pageflip delay if flip > 0 */
961*4882a593Smuzhiyun     if (!ms_queue_vblank(crtc, ms_flag, request_msc - flip, &queued_msc, seq)) {
962*4882a593Smuzhiyun         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
963*4882a593Smuzhiyun                    "final get vblank counter failed: %s\n",
964*4882a593Smuzhiyun                    strerror(errno));
965*4882a593Smuzhiyun         goto blit_fallback;
966*4882a593Smuzhiyun     }
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun     /* Adjust returned value for 1 fame pageflip offset of flip > 0 */
969*4882a593Smuzhiyun     *target_msc = queued_msc + flip;
970*4882a593Smuzhiyun     frame_info->frame = *target_msc;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun     return TRUE;
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun  blit_fallback:
975*4882a593Smuzhiyun     ms_dri2_blit_swap(draw, front, back);
976*4882a593Smuzhiyun     DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
977*4882a593Smuzhiyun     if (frame_info)
978*4882a593Smuzhiyun         ms_dri2_del_frame_event(frame_info);
979*4882a593Smuzhiyun     *target_msc = 0; /* offscreen, so zero out target vblank count */
980*4882a593Smuzhiyun     return TRUE;
981*4882a593Smuzhiyun }
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun static int
ms_dri2_frame_event_client_gone(void * data,XID id)984*4882a593Smuzhiyun ms_dri2_frame_event_client_gone(void *data, XID id)
985*4882a593Smuzhiyun {
986*4882a593Smuzhiyun     struct ms_dri2_resource *resource = data;
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun     while (!xorg_list_is_empty(&resource->list)) {
989*4882a593Smuzhiyun         ms_dri2_frame_event_ptr info =
990*4882a593Smuzhiyun             xorg_list_first_entry(&resource->list,
991*4882a593Smuzhiyun                                   ms_dri2_frame_event_rec,
992*4882a593Smuzhiyun                                   client_resource);
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun         xorg_list_del(&info->client_resource);
995*4882a593Smuzhiyun         info->client = NULL;
996*4882a593Smuzhiyun     }
997*4882a593Smuzhiyun     free(resource);
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun     return Success;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun static int
ms_dri2_frame_event_drawable_gone(void * data,XID id)1003*4882a593Smuzhiyun ms_dri2_frame_event_drawable_gone(void *data, XID id)
1004*4882a593Smuzhiyun {
1005*4882a593Smuzhiyun     struct ms_dri2_resource *resource = data;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun     while (!xorg_list_is_empty(&resource->list)) {
1008*4882a593Smuzhiyun         ms_dri2_frame_event_ptr info =
1009*4882a593Smuzhiyun             xorg_list_first_entry(&resource->list,
1010*4882a593Smuzhiyun                                   ms_dri2_frame_event_rec,
1011*4882a593Smuzhiyun                                   drawable_resource);
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun         xorg_list_del(&info->drawable_resource);
1014*4882a593Smuzhiyun         info->drawable = NULL;
1015*4882a593Smuzhiyun     }
1016*4882a593Smuzhiyun     free(resource);
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun     return Success;
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun static Bool
ms_dri2_register_frame_event_resource_types(void)1022*4882a593Smuzhiyun ms_dri2_register_frame_event_resource_types(void)
1023*4882a593Smuzhiyun {
1024*4882a593Smuzhiyun     frame_event_client_type =
1025*4882a593Smuzhiyun         CreateNewResourceType(ms_dri2_frame_event_client_gone,
1026*4882a593Smuzhiyun                               "Frame Event Client");
1027*4882a593Smuzhiyun     if (!frame_event_client_type)
1028*4882a593Smuzhiyun         return FALSE;
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun     frame_event_drawable_type =
1031*4882a593Smuzhiyun         CreateNewResourceType(ms_dri2_frame_event_drawable_gone,
1032*4882a593Smuzhiyun                               "Frame Event Drawable");
1033*4882a593Smuzhiyun     if (!frame_event_drawable_type)
1034*4882a593Smuzhiyun         return FALSE;
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun     return TRUE;
1037*4882a593Smuzhiyun }
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun Bool
ms_dri2_screen_init(ScreenPtr screen)1040*4882a593Smuzhiyun ms_dri2_screen_init(ScreenPtr screen)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1043*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
1044*4882a593Smuzhiyun     DRI2InfoRec info;
1045*4882a593Smuzhiyun     const char *driver_names[2] = { NULL, NULL };
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
1048*4882a593Smuzhiyun     if (ms->drmmode.glamor) {
1049*4882a593Smuzhiyun         if (!glamor_supports_pixmap_import_export(screen)) {
1050*4882a593Smuzhiyun             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1051*4882a593Smuzhiyun                        "DRI2: glamor lacks support for pixmap import/export\n");
1052*4882a593Smuzhiyun         }
1053*4882a593Smuzhiyun     }
1054*4882a593Smuzhiyun #endif
1055*4882a593Smuzhiyun 
1056*4882a593Smuzhiyun     if (!xf86LoaderCheckSymbol("DRI2Version"))
1057*4882a593Smuzhiyun         return FALSE;
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun     if (!dixRegisterPrivateKey(&ms_dri2_client_key,
1060*4882a593Smuzhiyun                                PRIVATE_CLIENT, sizeof(XID)))
1061*4882a593Smuzhiyun         return FALSE;
1062*4882a593Smuzhiyun 
1063*4882a593Smuzhiyun     if (serverGeneration != ms_dri2_server_generation) {
1064*4882a593Smuzhiyun         ms_dri2_server_generation = serverGeneration;
1065*4882a593Smuzhiyun         if (!ms_dri2_register_frame_event_resource_types()) {
1066*4882a593Smuzhiyun             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1067*4882a593Smuzhiyun                        "Cannot register DRI2 frame event resources\n");
1068*4882a593Smuzhiyun             return FALSE;
1069*4882a593Smuzhiyun         }
1070*4882a593Smuzhiyun     }
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun     memset(&info, '\0', sizeof(info));
1073*4882a593Smuzhiyun     info.fd = ms->fd;
1074*4882a593Smuzhiyun     info.driverName = NULL; /* Compat field, unused. */
1075*4882a593Smuzhiyun     info.deviceName = drmGetDeviceNameFromFd(ms->fd);
1076*4882a593Smuzhiyun     ms->drmmode.dri2_device_name = info.deviceName;
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun     info.version = 9;
1079*4882a593Smuzhiyun     info.CreateBuffer = ms_dri2_create_buffer;
1080*4882a593Smuzhiyun     info.DestroyBuffer = ms_dri2_destroy_buffer;
1081*4882a593Smuzhiyun     info.CopyRegion = ms_dri2_copy_region;
1082*4882a593Smuzhiyun     info.ScheduleSwap = ms_dri2_schedule_swap;
1083*4882a593Smuzhiyun     info.GetMSC = ms_dri2_get_msc;
1084*4882a593Smuzhiyun     info.ScheduleWaitMSC = ms_dri2_schedule_wait_msc;
1085*4882a593Smuzhiyun     info.CreateBuffer2 = ms_dri2_create_buffer2;
1086*4882a593Smuzhiyun     info.DestroyBuffer2 = ms_dri2_destroy_buffer2;
1087*4882a593Smuzhiyun     info.CopyRegion2 = ms_dri2_copy_region2;
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun     info.numDrivers = 0;
1090*4882a593Smuzhiyun     info.driverNames = NULL;
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun     return DRI2ScreenInit(screen, &info);
1093*4882a593Smuzhiyun }
1094*4882a593Smuzhiyun 
1095*4882a593Smuzhiyun void
ms_dri2_close_screen(ScreenPtr screen)1096*4882a593Smuzhiyun ms_dri2_close_screen(ScreenPtr screen)
1097*4882a593Smuzhiyun {
1098*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1099*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun     DRI2CloseScreen(screen);
1102*4882a593Smuzhiyun 
1103*4882a593Smuzhiyun     free((char *)ms->drmmode.dri2_device_name);
1104*4882a593Smuzhiyun }
1105