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