1 /**************************************************************************
2
3 Copyright 2001 VA Linux Systems Inc., Fremont, California.
4 Copyright © 2002 by David Dawes
5
6 All Rights Reserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 on the rights to use, copy, modify, merge, publish, distribute, sub
12 license, and/or sell copies of the Software, and to permit persons to whom
13 the Software is furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice (including the next
16 paragraph) shall be included in all copies or substantial portions of the
17 Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27 **************************************************************************/
28
29 /*
30 * Authors: Jeff Hartmann <jhartmann@valinux.com>
31 * David Dawes <dawes@xfree86.org>
32 * Keith Whitwell <keith@tungstengraphics.com>
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include <stdio.h>
40 #include <string.h>
41 #include <assert.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/ioctl.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <sys/time.h>
48 #include <time.h>
49 #include <errno.h>
50
51 #include "xorg-server.h"
52 #include "xf86.h"
53 #include "xf86_OSproc.h"
54
55 #include "xf86Pci.h"
56 #include "xf86drm.h"
57
58 #include "windowstr.h"
59 #include "shadow.h"
60 #include "fb.h"
61
62 #include "intel.h"
63 #include "i830_reg.h"
64
65 #include "i915_drm.h"
66
67 #include "dri2.h"
68
69 #if USE_UXA
70 #include "intel_uxa.h"
71 #endif
72
73 typedef struct {
74 int refcnt;
75 PixmapPtr pixmap;
76 } I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr;
77
78 #if HAS_DEVPRIVATEKEYREC
79 static DevPrivateKeyRec i830_client_key;
80 #else
81 static int i830_client_key;
82 #endif
83
84 static void I830DRI2FlipEventHandler(unsigned int frame,
85 unsigned int tv_sec,
86 unsigned int tv_usec,
87 DRI2FrameEventPtr flip_info);
88
89 static void I830DRI2FrameEventHandler(unsigned int frame,
90 unsigned int tv_sec,
91 unsigned int tv_usec,
92 DRI2FrameEventPtr swap_info);
93
94 static void
95 i830_dri2_del_frame_event(DRI2FrameEventPtr info);
96
pipe_select(int pipe)97 static uint32_t pipe_select(int pipe)
98 {
99 if (pipe > 1)
100 return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
101 else if (pipe > 0)
102 return DRM_VBLANK_SECONDARY;
103 else
104 return 0;
105 }
106
107 static void
intel_dri2_vblank_handler(ScrnInfoPtr scrn,xf86CrtcPtr crtc,uint64_t msc,uint64_t usec,void * data)108 intel_dri2_vblank_handler(ScrnInfoPtr scrn,
109 xf86CrtcPtr crtc,
110 uint64_t msc,
111 uint64_t usec,
112 void *data)
113 {
114 I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, data);
115 }
116
117 static void
intel_dri2_vblank_abort(ScrnInfoPtr scrn,xf86CrtcPtr crtc,void * data)118 intel_dri2_vblank_abort(ScrnInfoPtr scrn,
119 xf86CrtcPtr crtc,
120 void *data)
121 {
122 i830_dri2_del_frame_event(data);
123 }
124
pixmap_flink(PixmapPtr pixmap)125 static uint32_t pixmap_flink(PixmapPtr pixmap)
126 {
127 struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap);
128 uint32_t name;
129
130 if (priv == NULL || priv->bo == NULL)
131 return 0;
132
133 if (dri_bo_flink(priv->bo, &name) != 0)
134 return 0;
135
136 priv->pinned |= PIN_DRI2;
137 return name;
138 }
139
get_front_buffer(DrawablePtr drawable)140 static PixmapPtr get_front_buffer(DrawablePtr drawable)
141 {
142 PixmapPtr pixmap;
143
144 pixmap = get_drawable_pixmap(drawable);
145 if (!intel_get_pixmap_bo(pixmap))
146 return NULL;
147
148 pixmap->refcnt++;
149 return pixmap;
150 }
151
152 #if DRI2INFOREC_VERSION < 2
153 static DRI2BufferPtr
I830DRI2CreateBuffers(DrawablePtr drawable,unsigned int * attachments,int count)154 I830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments,
155 int count)
156 {
157 ScreenPtr screen = drawable->pScreen;
158 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
159 intel_screen_private *intel = intel_get_screen_private(scrn);
160 DRI2BufferPtr buffers;
161 I830DRI2BufferPrivatePtr privates;
162 PixmapPtr pixmap, pDepthPixmap;
163 int i;
164
165 buffers = calloc(count, sizeof *buffers);
166 if (buffers == NULL)
167 return NULL;
168 privates = calloc(count, sizeof *privates);
169 if (privates == NULL) {
170 free(buffers);
171 return NULL;
172 }
173
174 pDepthPixmap = NULL;
175 for (i = 0; i < count; i++) {
176 pixmap = NULL;
177 if (attachments[i] == DRI2BufferFrontLeft) {
178 pixmap = get_front_buffer(drawable);
179 } else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) {
180 pixmap = pDepthPixmap;
181 pixmap->refcnt++;
182 }
183
184 if (pixmap == NULL) {
185 unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
186
187 if (intel->tiling & INTEL_TILING_3D) {
188 switch (attachments[i]) {
189 case DRI2BufferDepth:
190 if (SUPPORTS_YTILING(intel))
191 hint |= INTEL_CREATE_PIXMAP_TILING_Y;
192 else
193 hint |= INTEL_CREATE_PIXMAP_TILING_X;
194 break;
195 case DRI2BufferFakeFrontLeft:
196 case DRI2BufferFakeFrontRight:
197 case DRI2BufferBackLeft:
198 case DRI2BufferBackRight:
199 hint |= INTEL_CREATE_PIXMAP_TILING_X;
200 break;
201 }
202 }
203
204 pixmap = screen->CreatePixmap(screen,
205 drawable->width,
206 drawable->height,
207 drawable->depth,
208 hint);
209 if (pixmap == NULL ||
210 intel_get_pixmap_bo(pixmap) == NULL)
211 {
212 if (pixmap)
213 screen->DestroyPixmap(pixmap);
214 goto unwind;
215 }
216 }
217
218 if (attachments[i] == DRI2BufferDepth)
219 pDepthPixmap = pixmap;
220
221 buffers[i].attachment = attachments[i];
222 buffers[i].pitch = pixmap->devKind;
223 buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8;
224 buffers[i].driverPrivate = &privates[i];
225 buffers[i].flags = 0; /* not tiled */
226 privates[i].refcnt = 1;
227 privates[i].pixmap = pixmap;
228
229 if ((buffers[i].name = pixmap_flink(pixmap)) == 0) {
230 /* failed to name buffer */
231 screen->DestroyPixmap(pixmap);
232 goto unwind;
233 }
234 }
235
236 return buffers;
237
238 unwind:
239 while (i--)
240 screen->DestroyPixmap(privates[i].pixmap);
241 free(privates);
242 free(buffers);
243 return NULL;
244 }
245
246 static void
I830DRI2DestroyBuffers(DrawablePtr drawable,DRI2BufferPtr buffers,int count)247 I830DRI2DestroyBuffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
248 {
249 ScreenPtr screen = drawable->pScreen;
250 I830DRI2BufferPrivatePtr private;
251 int i;
252
253 for (i = 0; i < count; i++) {
254 private = buffers[i].driverPrivate;
255 screen->DestroyPixmap(private->pixmap);
256 }
257
258 if (buffers) {
259 free(buffers[0].driverPrivate);
260 free(buffers);
261 }
262 }
263
264 #else
265
266 static DRI2Buffer2Ptr
I830DRI2CreateBuffer(DrawablePtr drawable,unsigned int attachment,unsigned int format)267 I830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment,
268 unsigned int format)
269 {
270 ScreenPtr screen = drawable->pScreen;
271 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
272 intel_screen_private *intel = intel_get_screen_private(scrn);
273 DRI2Buffer2Ptr buffer;
274 I830DRI2BufferPrivatePtr privates;
275 PixmapPtr pixmap;
276
277 buffer = calloc(1, sizeof *buffer);
278 if (buffer == NULL)
279 return NULL;
280 privates = calloc(1, sizeof *privates);
281 if (privates == NULL) {
282 free(buffer);
283 return NULL;
284 }
285
286 pixmap = NULL;
287 if (attachment == DRI2BufferFrontLeft)
288 pixmap = get_front_buffer(drawable);
289
290 if (pixmap == NULL) {
291 unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
292 int pixmap_width = drawable->width;
293 int pixmap_height = drawable->height;
294 int pixmap_cpp = (format != 0) ? format : drawable->depth;
295
296 if (intel->tiling & INTEL_TILING_3D) {
297 switch (attachment) {
298 case DRI2BufferDepth:
299 case DRI2BufferDepthStencil:
300 case DRI2BufferHiz:
301 if (SUPPORTS_YTILING(intel)) {
302 hint |= INTEL_CREATE_PIXMAP_TILING_Y;
303 break;
304 }
305 /* fall through */
306 case DRI2BufferAccum:
307 case DRI2BufferBackLeft:
308 case DRI2BufferBackRight:
309 case DRI2BufferFakeFrontLeft:
310 case DRI2BufferFakeFrontRight:
311 case DRI2BufferFrontLeft:
312 case DRI2BufferFrontRight:
313 hint |= INTEL_CREATE_PIXMAP_TILING_X;
314 break;
315 case DRI2BufferStencil:
316 /*
317 * The stencil buffer is W tiled. However, we
318 * request from the kernel a non-tiled buffer
319 * because the GTT is incapable of W fencing.
320 */
321 hint |= INTEL_CREATE_PIXMAP_TILING_NONE;
322 break;
323 default:
324 free(privates);
325 free(buffer);
326 return NULL;
327 }
328 }
329
330 /*
331 * The stencil buffer has quirky pitch requirements. From Vol
332 * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface
333 * Pitch":
334 * The pitch must be set to 2x the value computed based on
335 * width, as the stencil buffer is stored with two rows
336 * interleaved.
337 * To accomplish this, we resort to the nasty hack of doubling
338 * the drm region's cpp and halving its height.
339 *
340 * If we neglect to double the pitch, then render corruption
341 * occurs.
342 */
343 if (attachment == DRI2BufferStencil) {
344 pixmap_width = ALIGN(pixmap_width, 64);
345 pixmap_height = ALIGN((pixmap_height + 1) / 2, 64);
346 pixmap_cpp *= 2;
347 }
348
349 pixmap = screen->CreatePixmap(screen,
350 pixmap_width,
351 pixmap_height,
352 pixmap_cpp,
353 hint);
354 if (pixmap == NULL || intel_get_pixmap_bo(pixmap) == NULL) {
355 if (pixmap)
356 screen->DestroyPixmap(pixmap);
357 free(privates);
358 free(buffer);
359 return NULL;
360 }
361 }
362
363 buffer->attachment = attachment;
364 buffer->pitch = pixmap->devKind;
365 buffer->cpp = pixmap->drawable.bitsPerPixel / 8;
366 buffer->driverPrivate = privates;
367 buffer->format = format;
368 buffer->flags = 0; /* not tiled */
369 privates->refcnt = 1;
370 privates->pixmap = pixmap;
371
372 if ((buffer->name = pixmap_flink(pixmap)) == 0) {
373 /* failed to name buffer */
374 screen->DestroyPixmap(pixmap);
375 free(privates);
376 free(buffer);
377 return NULL;
378 }
379
380 return buffer;
381 }
382
I830DRI2DestroyBuffer(DrawablePtr drawable,DRI2Buffer2Ptr buffer)383 static void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
384 {
385 if (buffer && buffer->driverPrivate) {
386 I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
387 if (--private->refcnt == 0) {
388 ScreenPtr screen = private->pixmap->drawable.pScreen;
389 screen->DestroyPixmap(private->pixmap);
390
391 free(private);
392 free(buffer);
393 }
394 } else
395 free(buffer);
396 }
397
398 #endif
399
400 static void
I830DRI2CopyRegion(DrawablePtr drawable,RegionPtr pRegion,DRI2BufferPtr destBuffer,DRI2BufferPtr sourceBuffer)401 I830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion,
402 DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
403 {
404 I830DRI2BufferPrivatePtr srcPrivate = sourceBuffer->driverPrivate;
405 I830DRI2BufferPrivatePtr dstPrivate = destBuffer->driverPrivate;
406 ScreenPtr screen = drawable->pScreen;
407 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
408 intel_screen_private *intel = intel_get_screen_private(scrn);
409 DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft)
410 ? drawable : &srcPrivate->pixmap->drawable;
411 DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft)
412 ? drawable : &dstPrivate->pixmap->drawable;
413 RegionPtr pCopyClip;
414 GCPtr gc;
415
416 gc = GetScratchGC(dst->depth, screen);
417 if (!gc)
418 return;
419
420 pCopyClip = REGION_CREATE(screen, NULL, 0);
421 REGION_COPY(screen, pCopyClip, pRegion);
422 (*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0);
423 ValidateGC(dst, gc);
424
425 /* Wait for the scanline to be outside the region to be copied */
426 if (scrn->vtSema &&
427 pixmap_is_scanout(get_drawable_pixmap(dst)) &&
428 intel->swapbuffers_wait && INTEL_INFO(intel)->gen < 060) {
429 BoxPtr box;
430 BoxRec crtcbox;
431 int y1, y2;
432 int event, load_scan_lines_pipe;
433 xf86CrtcPtr crtc;
434 Bool full_height = FALSE;
435
436 box = REGION_EXTENTS(unused, gc->pCompositeClip);
437 crtc = intel_covering_crtc(scrn, box, NULL, &crtcbox);
438
439 /*
440 * Make sure the CRTC is valid and this is the real front
441 * buffer
442 */
443 if (crtc != NULL && !crtc->rotatedData) {
444 int pipe = intel_crtc_to_pipe(crtc);
445
446 /*
447 * Make sure we don't wait for a scanline that will
448 * never occur
449 */
450 y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0;
451 y2 = (box->y2 <= crtcbox.y2) ?
452 box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1;
453
454 if (y1 == 0 && y2 == (crtcbox.y2 - crtcbox.y1))
455 full_height = TRUE;
456
457 /*
458 * Pre-965 doesn't have SVBLANK, so we need a bit
459 * of extra time for the blitter to start up and
460 * do its job for a full height blit
461 */
462 if (full_height && INTEL_INFO(intel)->gen < 040)
463 y2 -= 2;
464
465 if (pipe == 0) {
466 event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
467 load_scan_lines_pipe =
468 MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
469 if (full_height && INTEL_INFO(intel)->gen >= 040)
470 event = MI_WAIT_FOR_PIPEA_SVBLANK;
471 } else {
472 event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
473 load_scan_lines_pipe =
474 MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
475 if (full_height && INTEL_INFO(intel)->gen >= 040)
476 event = MI_WAIT_FOR_PIPEB_SVBLANK;
477 }
478
479 if (crtc->mode.Flags & V_INTERLACE) {
480 /* DSL count field lines */
481 y1 /= 2;
482 y2 /= 2;
483 }
484
485 BEGIN_BATCH(5);
486 /*
487 * The documentation says that the LOAD_SCAN_LINES
488 * command always comes in pairs. Don't ask me why.
489 */
490 OUT_BATCH(MI_LOAD_SCAN_LINES_INCL |
491 load_scan_lines_pipe);
492 OUT_BATCH((y1 << 16) | (y2-1));
493 OUT_BATCH(MI_LOAD_SCAN_LINES_INCL |
494 load_scan_lines_pipe);
495 OUT_BATCH((y1 << 16) | (y2-1));
496 OUT_BATCH(MI_WAIT_FOR_EVENT | event);
497 ADVANCE_BATCH();
498 }
499 }
500
501 /* It's important that this copy gets submitted before the
502 * direct rendering client submits rendering for the next
503 * frame, but we don't actually need to submit right now. The
504 * client will wait for the DRI2CopyRegion reply or the swap
505 * buffer event before rendering, and we'll hit the flush
506 * callback chain before those messages are sent. We submit
507 * our batch buffers from the flush callback chain so we know
508 * that will happen before the client tries to render
509 * again. */
510
511 gc->ops->CopyArea(src, dst, gc,
512 0, 0,
513 drawable->width, drawable->height,
514 0, 0);
515
516 FreeScratchGC(gc);
517
518 /* And make sure the WAIT_FOR_EVENT is queued before any
519 * modesetting/dpms operations on the pipe.
520 */
521 intel_batch_submit(scrn);
522 }
523
524 static void
I830DRI2FallbackBlitSwap(DrawablePtr drawable,DRI2BufferPtr dst,DRI2BufferPtr src)525 I830DRI2FallbackBlitSwap(DrawablePtr drawable,
526 DRI2BufferPtr dst,
527 DRI2BufferPtr src)
528 {
529 BoxRec box;
530 RegionRec region;
531
532 box.x1 = 0;
533 box.y1 = 0;
534 box.x2 = drawable->width;
535 box.y2 = drawable->height;
536 REGION_INIT(pScreen, ®ion, &box, 0);
537
538 I830DRI2CopyRegion(drawable, ®ion, dst, src);
539 }
540
541 #if DRI2INFOREC_VERSION >= 4
542
I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer)543 static void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer)
544 {
545 if (buffer) {
546 I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
547 private->refcnt++;
548 }
549 }
550
551 static xf86CrtcPtr
I830DRI2DrawableCrtc(DrawablePtr pDraw)552 I830DRI2DrawableCrtc(DrawablePtr pDraw)
553 {
554 ScreenPtr pScreen = pDraw->pScreen;
555 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
556 BoxRec box, crtcbox;
557 xf86CrtcPtr crtc = NULL;
558
559 box.x1 = pDraw->x;
560 box.y1 = pDraw->y;
561 box.x2 = box.x1 + pDraw->width;
562 box.y2 = box.y1 + pDraw->height;
563
564 if (pDraw->type != DRAWABLE_PIXMAP)
565 crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox);
566
567 /* Make sure the CRTC is valid and this is the real front buffer */
568 if (crtc != NULL && !crtc->rotatedData)
569 return crtc;
570
571 return NULL;
572 }
573
574 static RESTYPE frame_event_client_type, frame_event_drawable_type;
575
576 struct i830_dri2_resource {
577 XID id;
578 RESTYPE type;
579 struct list list;
580 };
581
582 static struct i830_dri2_resource *
get_resource(XID id,RESTYPE type)583 get_resource(XID id, RESTYPE type)
584 {
585 struct i830_dri2_resource *resource;
586 void *ptr;
587
588 ptr = NULL;
589 dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess);
590 if (ptr)
591 return ptr;
592
593 resource = malloc(sizeof(*resource));
594 if (resource == NULL)
595 return NULL;
596
597 if (!AddResource(id, type, resource)) {
598 free(resource);
599 return NULL;
600 }
601
602 resource->id = id;
603 resource->type = type;
604 list_init(&resource->list);
605 return resource;
606 }
607
608 static int
i830_dri2_frame_event_client_gone(void * data,XID id)609 i830_dri2_frame_event_client_gone(void *data, XID id)
610 {
611 struct i830_dri2_resource *resource = data;
612
613 while (!list_is_empty(&resource->list)) {
614 DRI2FrameEventPtr info =
615 list_first_entry(&resource->list,
616 DRI2FrameEventRec,
617 client_resource);
618
619 list_del(&info->client_resource);
620 info->client = NULL;
621 }
622 free(resource);
623
624 return Success;
625 }
626
627 static int
i830_dri2_frame_event_drawable_gone(void * data,XID id)628 i830_dri2_frame_event_drawable_gone(void *data, XID id)
629 {
630 struct i830_dri2_resource *resource = data;
631
632 while (!list_is_empty(&resource->list)) {
633 DRI2FrameEventPtr info =
634 list_first_entry(&resource->list,
635 DRI2FrameEventRec,
636 drawable_resource);
637
638 list_del(&info->drawable_resource);
639 info->drawable_id = None;
640 }
641 free(resource);
642
643 return Success;
644 }
645
646 static Bool
i830_dri2_register_frame_event_resource_types(void)647 i830_dri2_register_frame_event_resource_types(void)
648 {
649 frame_event_client_type = CreateNewResourceType(i830_dri2_frame_event_client_gone, "Frame Event Client");
650 if (!frame_event_client_type)
651 return FALSE;
652
653 frame_event_drawable_type = CreateNewResourceType(i830_dri2_frame_event_drawable_gone, "Frame Event Drawable");
654 if (!frame_event_drawable_type)
655 return FALSE;
656
657 return TRUE;
658 }
659
660 static XID
get_client_id(ClientPtr client)661 get_client_id(ClientPtr client)
662 {
663 #if HAS_DIXREGISTERPRIVATEKEY
664 XID *ptr = dixGetPrivateAddr(&client->devPrivates, &i830_client_key);
665 #else
666 XID *ptr = dixLookupPrivate(&client->devPrivates, &i830_client_key);
667 #endif
668 if (*ptr == 0)
669 *ptr = FakeClientID(client->index);
670 return *ptr;
671 }
672
673 /*
674 * Hook this frame event into the server resource
675 * database so we can clean it up if the drawable or
676 * client exits while the swap is pending
677 */
678 static Bool
i830_dri2_add_frame_event(DRI2FrameEventPtr info)679 i830_dri2_add_frame_event(DRI2FrameEventPtr info)
680 {
681 struct i830_dri2_resource *resource;
682
683 resource = get_resource(get_client_id(info->client),
684 frame_event_client_type);
685 if (resource == NULL)
686 return FALSE;
687
688 list_add(&info->client_resource, &resource->list);
689
690 resource = get_resource(info->drawable_id, frame_event_drawable_type);
691 if (resource == NULL) {
692 list_del(&info->client_resource);
693 return FALSE;
694 }
695
696 list_add(&info->drawable_resource, &resource->list);
697
698 return TRUE;
699 }
700
701 static void
i830_dri2_del_frame_event(DRI2FrameEventPtr info)702 i830_dri2_del_frame_event(DRI2FrameEventPtr info)
703 {
704 list_del(&info->client_resource);
705 list_del(&info->drawable_resource);
706
707 if (info->front)
708 I830DRI2DestroyBuffer(NULL, info->front);
709 if (info->back)
710 I830DRI2DestroyBuffer(NULL, info->back);
711
712 if (info->old_buffer) {
713 /* Check that the old buffer still matches the front buffer
714 * in case a mode change occurred before we woke up.
715 */
716 if (info->intel->back_buffer == NULL &&
717 info->old_width == info->intel->scrn->virtualX &&
718 info->old_height == info->intel->scrn->virtualY &&
719 info->old_pitch == info->intel->front_pitch &&
720 info->old_tiling == info->intel->front_tiling)
721 info->intel->back_buffer = info->old_buffer;
722 else
723 dri_bo_unreference(info->old_buffer);
724 }
725
726 free(info);
727 }
728
729 static struct intel_uxa_pixmap *
intel_exchange_pixmap_buffers(struct intel_screen_private * intel,PixmapPtr front,PixmapPtr back)730 intel_exchange_pixmap_buffers(struct intel_screen_private *intel, PixmapPtr front, PixmapPtr back)
731 {
732 struct intel_uxa_pixmap *new_front = NULL, *new_back;
733 RegionRec region;
734
735 /* Post damage on the front buffer so that listeners, such
736 * as DisplayLink know take a copy and shove it over the USB.
737 * also for sw cursors.
738 */
739 region.extents.x1 = region.extents.y1 = 0;
740 region.extents.x2 = front->drawable.width;
741 region.extents.y2 = front->drawable.height;
742 region.data = NULL;
743 DamageRegionAppend(&front->drawable, ®ion);
744
745 new_front = intel_uxa_get_pixmap_private(back);
746 new_back = intel_uxa_get_pixmap_private(front);
747 intel_uxa_set_pixmap_private(front, new_front);
748 intel_uxa_set_pixmap_private(back, new_back);
749 new_front->busy = 1;
750 new_back->busy = -1;
751
752 DamageRegionProcessPending(&front->drawable);
753
754 return new_front;
755 }
756
757 static void
I830DRI2ExchangeBuffers(struct intel_screen_private * intel,DRI2BufferPtr front,DRI2BufferPtr back)758 I830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back)
759 {
760 I830DRI2BufferPrivatePtr front_priv, back_priv;
761 struct intel_uxa_pixmap *new_front;
762
763 front_priv = front->driverPrivate;
764 back_priv = back->driverPrivate;
765
766 /* Swap BO names so DRI works */
767 front->name = back->name;
768 back->name = pixmap_flink(front_priv->pixmap);
769
770 /* Swap pixmap bos */
771 new_front = intel_exchange_pixmap_buffers(intel,
772 front_priv->pixmap,
773 back_priv->pixmap);
774 dri_bo_unreference (intel->front_buffer);
775 intel->front_buffer = new_front->bo;
776 dri_bo_reference (intel->front_buffer);
777 }
778
get_pixmap_bo(I830DRI2BufferPrivatePtr priv)779 static drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv)
780 {
781 drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap);
782 assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */
783 return bo;
784 }
785
786 static void
I830DRI2FlipComplete(uint64_t frame,uint64_t usec,void * pageflip_data)787 I830DRI2FlipComplete(uint64_t frame, uint64_t usec, void *pageflip_data)
788 {
789 DRI2FrameEventPtr info = pageflip_data;
790
791 I830DRI2FlipEventHandler((uint32_t) frame, usec / 1000000,
792 usec % 1000000,
793 info);
794 }
795
796 static void
I830DRI2FlipAbort(void * pageflip_data)797 I830DRI2FlipAbort(void *pageflip_data)
798 {
799 DRI2FrameEventPtr info = pageflip_data;
800
801 i830_dri2_del_frame_event(info);
802 }
803
804 static Bool
allocate_back_buffer(struct intel_screen_private * intel)805 allocate_back_buffer(struct intel_screen_private *intel)
806 {
807 drm_intel_bo *bo;
808 int pitch;
809 uint32_t tiling;
810
811 if (intel->back_buffer)
812 return TRUE;
813
814 bo = intel_allocate_framebuffer(intel->scrn,
815 intel->scrn->virtualX,
816 intel->scrn->virtualY,
817 intel->cpp,
818 &pitch, &tiling);
819 if (bo == NULL)
820 return FALSE;
821
822 if (pitch != intel->front_pitch || tiling != intel->front_tiling) {
823 drm_intel_bo_unreference(bo);
824 return FALSE;
825 }
826
827 intel->back_buffer = bo;
828 return TRUE;
829 }
830
831 static Bool
can_exchange(DrawablePtr drawable,DRI2BufferPtr front,DRI2BufferPtr back)832 can_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
833 {
834 ScrnInfoPtr pScrn = xf86ScreenToScrn(drawable->pScreen);
835 struct intel_screen_private *intel = intel_get_screen_private(pScrn);
836 I830DRI2BufferPrivatePtr front_priv = front->driverPrivate;
837 I830DRI2BufferPrivatePtr back_priv = back->driverPrivate;
838 PixmapPtr front_pixmap = front_priv->pixmap;
839 PixmapPtr back_pixmap = back_priv->pixmap;
840 struct intel_uxa_pixmap *front_intel = intel_uxa_get_pixmap_private(front_pixmap);
841 struct intel_uxa_pixmap *back_intel = intel_uxa_get_pixmap_private(back_pixmap);
842
843 if (!pScrn->vtSema)
844 return FALSE;
845
846 if (I830DRI2DrawableCrtc(drawable) == NULL)
847 return FALSE;
848
849 if (!DRI2CanFlip(drawable))
850 return FALSE;
851
852 if (intel->shadow_present)
853 return FALSE;
854
855 if (!intel->use_pageflipping)
856 return FALSE;
857
858 if (front_pixmap->drawable.width != back_pixmap->drawable.width)
859 return FALSE;
860
861 if (front_pixmap->drawable.height != back_pixmap->drawable.height)
862 return FALSE;
863
864 /* XXX should we be checking depth instead of bpp? */
865 #if 0
866 if (front_pixmap->drawable.depth != back_pixmap->drawable.depth)
867 return FALSE;
868 #else
869 if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel)
870 return FALSE;
871 #endif
872
873 /* prevent an implicit tiling mode change */
874 if (front_intel->tiling != back_intel->tiling)
875 return FALSE;
876
877 if (front_intel->pinned & ~(PIN_SCANOUT | PIN_DRI2))
878 return FALSE;
879
880 return TRUE;
881 }
882
883 static Bool
queue_flip(struct intel_screen_private * intel,DrawablePtr draw,DRI2FrameEventPtr info)884 queue_flip(struct intel_screen_private *intel,
885 DrawablePtr draw,
886 DRI2FrameEventPtr info)
887 {
888 xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
889 I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
890 drm_intel_bo *old_back = get_pixmap_bo(priv);
891
892 if (crtc == NULL)
893 return FALSE;
894
895 if (!can_exchange(draw, info->front, info->back))
896 return FALSE;
897
898 if (!intel_do_pageflip(intel, old_back,
899 intel_crtc_to_pipe(crtc),
900 FALSE, info,
901 I830DRI2FlipComplete, I830DRI2FlipAbort))
902 return FALSE;
903
904 #if DRI2INFOREC_VERSION >= 6
905 if (intel->use_triple_buffer && allocate_back_buffer(intel)) {
906 info->old_width = intel->scrn->virtualX;
907 info->old_height = intel->scrn->virtualY;
908 info->old_pitch = intel->front_pitch;
909 info->old_tiling = intel->front_tiling;
910 info->old_buffer = intel->front_buffer;
911 dri_bo_reference(info->old_buffer);
912
913 priv = info->front->driverPrivate;
914 intel_set_pixmap_bo(priv->pixmap, intel->back_buffer);
915
916 dri_bo_unreference(intel->back_buffer);
917 intel->back_buffer = NULL;
918
919 DRI2SwapLimit(draw, 2);
920 } else
921 DRI2SwapLimit(draw, 1);
922 #endif
923
924 /* Then flip DRI2 pointers and update the screen pixmap */
925 I830DRI2ExchangeBuffers(intel, info->front, info->back);
926 return TRUE;
927 }
928
929 static Bool
queue_swap(struct intel_screen_private * intel,DrawablePtr draw,DRI2FrameEventPtr info)930 queue_swap(struct intel_screen_private *intel,
931 DrawablePtr draw,
932 DRI2FrameEventPtr info)
933 {
934 xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
935 drmVBlank vbl;
936
937 if (crtc == NULL)
938 return FALSE;
939
940 vbl.request.type =
941 DRM_VBLANK_RELATIVE |
942 DRM_VBLANK_EVENT |
943 pipe_select(intel_crtc_to_pipe(crtc));
944 vbl.request.sequence = 1;
945 vbl.request.signal =
946 intel_drm_queue_alloc(intel->scrn, crtc, info,
947 intel_dri2_vblank_handler,
948 intel_dri2_vblank_abort);
949 if (vbl.request.signal == 0)
950 return FALSE;
951
952 info->type = DRI2_SWAP;
953 if (drmWaitVBlank(intel->drmSubFD, &vbl)) {
954 intel_drm_abort_seq(intel->scrn, vbl.request.signal);
955 return FALSE;
956 }
957
958 return TRUE;
959 }
960
I830DRI2FrameEventHandler(unsigned int frame,unsigned int tv_sec,unsigned int tv_usec,DRI2FrameEventPtr swap_info)961 static void I830DRI2FrameEventHandler(unsigned int frame,
962 unsigned int tv_sec,
963 unsigned int tv_usec,
964 DRI2FrameEventPtr swap_info)
965 {
966 intel_screen_private *intel = swap_info->intel;
967 DrawablePtr drawable;
968 int status;
969
970 if (!swap_info->drawable_id)
971 status = BadDrawable;
972 else
973 status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient,
974 M_ANY, DixWriteAccess);
975 if (status != Success) {
976 i830_dri2_del_frame_event(swap_info);
977 return;
978 }
979
980 switch (swap_info->type) {
981 case DRI2_FLIP:
982 /* If we can still flip... */
983 if (!queue_flip(intel, drawable, swap_info) &&
984 !queue_swap(intel, drawable, swap_info)) {
985 case DRI2_SWAP:
986 I830DRI2FallbackBlitSwap(drawable,
987 swap_info->front, swap_info->back);
988 DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
989 DRI2_BLIT_COMPLETE,
990 swap_info->client ? swap_info->event_complete : NULL,
991 swap_info->event_data);
992 break;
993 }
994 return;
995
996 case DRI2_WAITMSC:
997 if (swap_info->client)
998 DRI2WaitMSCComplete(swap_info->client, drawable,
999 frame, tv_sec, tv_usec);
1000 break;
1001 default:
1002 xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
1003 "%s: unknown vblank event received\n", __func__);
1004 /* Unknown type */
1005 break;
1006 }
1007
1008 i830_dri2_del_frame_event(swap_info);
1009 }
1010
I830DRI2FlipEventHandler(unsigned int frame,unsigned int tv_sec,unsigned int tv_usec,DRI2FrameEventPtr flip_info)1011 static void I830DRI2FlipEventHandler(unsigned int frame,
1012 unsigned int tv_sec,
1013 unsigned int tv_usec,
1014 DRI2FrameEventPtr flip_info)
1015 {
1016 struct intel_screen_private *intel = flip_info->intel;
1017 DrawablePtr drawable;
1018
1019 drawable = NULL;
1020 if (flip_info->drawable_id)
1021 dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient,
1022 M_ANY, DixWriteAccess);
1023
1024
1025 /* We assume our flips arrive in order, so we don't check the frame */
1026 switch (flip_info->type) {
1027 case DRI2_FLIP:
1028 case DRI2_SWAP:
1029 if (!drawable)
1030 break;
1031
1032 /* Check for too small vblank count of pageflip completion, taking wraparound
1033 * into account. This usually means some defective kms pageflip completion,
1034 * causing wrong (msc, ust) return values and possible visual corruption.
1035 */
1036 if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) {
1037 static int limit = 5;
1038
1039 /* XXX we are currently hitting this path with older
1040 * kernels, so make it quieter.
1041 */
1042 if (limit) {
1043 xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
1044 "%s: Pageflip completion has impossible msc %d < target_msc %d\n",
1045 __func__, frame, flip_info->frame);
1046 limit--;
1047 }
1048
1049 /* All-0 values signal timestamping failure. */
1050 frame = tv_sec = tv_usec = 0;
1051 }
1052
1053 DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec,
1054 DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL,
1055 flip_info->event_data);
1056 break;
1057
1058 default:
1059 xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
1060 "%s: unknown vblank event received\n", __func__);
1061 /* Unknown type */
1062 break;
1063 }
1064
1065 i830_dri2_del_frame_event(flip_info);
1066 }
1067
1068 /*
1069 * ScheduleSwap is responsible for requesting a DRM vblank event for the
1070 * appropriate frame.
1071 *
1072 * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
1073 * the vblank requested can simply be the last queued swap frame + the swap
1074 * interval for the drawable.
1075 *
1076 * In the case of a page flip, we request an event for the last queued swap
1077 * frame + swap interval - 1, since we'll need to queue the flip for the frame
1078 * immediately following the received event.
1079 *
1080 * The client will be blocked if it tries to perform further GL commands
1081 * after queueing a swap, though in the Intel case after queueing a flip, the
1082 * client is free to queue more commands; they'll block in the kernel if
1083 * they access buffers busy with the flip.
1084 *
1085 * When the swap is complete, the driver should call into the server so it
1086 * can send any swap complete events that have been requested.
1087 */
1088 static int
I830DRI2ScheduleSwap(ClientPtr client,DrawablePtr draw,DRI2BufferPtr front,DRI2BufferPtr back,CARD64 * target_msc,CARD64 divisor,CARD64 remainder,DRI2SwapEventPtr func,void * data)1089 I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
1090 DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
1091 CARD64 remainder, DRI2SwapEventPtr func, void *data)
1092 {
1093 ScreenPtr screen = draw->pScreen;
1094 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1095 intel_screen_private *intel = intel_get_screen_private(scrn);
1096 drmVBlank vbl;
1097 int ret;
1098 xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
1099 int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
1100 int flip = 0;
1101 DRI2FrameEventPtr swap_info = NULL;
1102 uint64_t current_msc, current_ust;
1103 uint64_t request_msc;
1104 uint32_t seq;
1105
1106 /* Drawable not displayed... just complete the swap */
1107 if (pipe == -1)
1108 goto blit_fallback;
1109
1110 swap_info = calloc(1, sizeof(DRI2FrameEventRec));
1111 if (!swap_info)
1112 goto blit_fallback;
1113
1114 swap_info->intel = intel;
1115 swap_info->drawable_id = draw->id;
1116 swap_info->client = client;
1117 swap_info->event_complete = func;
1118 swap_info->event_data = data;
1119 swap_info->front = front;
1120 swap_info->back = back;
1121 swap_info->type = DRI2_SWAP;
1122
1123 if (!i830_dri2_add_frame_event(swap_info)) {
1124 free(swap_info);
1125 swap_info = NULL;
1126 goto blit_fallback;
1127 }
1128
1129 I830DRI2ReferenceBuffer(front);
1130 I830DRI2ReferenceBuffer(back);
1131
1132 ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust);
1133 if (ret)
1134 goto blit_fallback;
1135
1136 /*
1137 * If we can, schedule the flip directly from here rather
1138 * than waiting for an event from the kernel for the current
1139 * (or a past) MSC.
1140 */
1141 if (divisor == 0 &&
1142 current_msc >= *target_msc &&
1143 queue_flip(intel, draw, swap_info))
1144 return TRUE;
1145
1146 if (can_exchange(draw, front, back)) {
1147 swap_info->type = DRI2_FLIP;
1148 /* Flips need to be submitted one frame before */
1149 if (*target_msc > 0)
1150 --*target_msc;
1151 flip = 1;
1152 }
1153
1154 #if DRI2INFOREC_VERSION >= 6
1155 DRI2SwapLimit(draw, 1);
1156 #endif
1157
1158 /*
1159 * If divisor is zero, or current_msc is smaller than target_msc
1160 * we just need to make sure target_msc passes before initiating
1161 * the swap.
1162 */
1163 if (divisor == 0 || current_msc < *target_msc) {
1164 vbl.request.type =
1165 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
1166
1167 /* If non-pageflipping, but blitting/exchanging, we need to use
1168 * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
1169 * on.
1170 */
1171 if (flip == 0)
1172 vbl.request.type |= DRM_VBLANK_NEXTONMISS;
1173
1174 /* If target_msc already reached or passed, set it to
1175 * current_msc to ensure we return a reasonable value back
1176 * to the caller. This makes swap_interval logic more robust.
1177 */
1178 if (current_msc > *target_msc)
1179 *target_msc = current_msc;
1180
1181 seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
1182 if (!seq)
1183 goto blit_fallback;
1184
1185 vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc);
1186 vbl.request.signal = seq;
1187
1188 ret = drmWaitVBlank(intel->drmSubFD, &vbl);
1189 if (ret) {
1190 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1191 "divisor 0 get vblank counter failed: %s\n",
1192 strerror(errno));
1193 intel_drm_abort_seq(intel->scrn, seq);
1194 swap_info = NULL;
1195 goto blit_fallback;
1196 }
1197
1198 *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
1199 swap_info->frame = *target_msc;
1200
1201 return TRUE;
1202 }
1203
1204 /*
1205 * If we get here, target_msc has already passed or we don't have one,
1206 * and we need to queue an event that will satisfy the divisor/remainder
1207 * equation.
1208 */
1209 vbl.request.type =
1210 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
1211 if (flip == 0)
1212 vbl.request.type |= DRM_VBLANK_NEXTONMISS;
1213
1214 request_msc = current_msc - (current_msc % divisor) +
1215 remainder;
1216
1217 /*
1218 * If the calculated deadline vbl.request.sequence is smaller than
1219 * or equal to current_msc, it means we've passed the last point
1220 * when effective onset frame seq could satisfy
1221 * seq % divisor == remainder, so we need to wait for the next time
1222 * this will happen.
1223
1224 * This comparison takes the 1 frame swap delay in pageflipping mode
1225 * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
1226 * if we are blitting/exchanging instead of flipping.
1227 */
1228 if (request_msc <= current_msc)
1229 request_msc += divisor;
1230
1231 seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
1232 if (!seq)
1233 goto blit_fallback;
1234
1235 /* Account for 1 frame extra pageflip delay if flip > 0 */
1236 vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc) - flip;
1237 vbl.request.signal = seq;
1238
1239 ret = drmWaitVBlank(intel->drmSubFD, &vbl);
1240 if (ret) {
1241 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1242 "final get vblank counter failed: %s\n",
1243 strerror(errno));
1244 goto blit_fallback;
1245 }
1246
1247 /* Adjust returned value for 1 fame pageflip offset of flip > 0 */
1248 *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
1249 swap_info->frame = *target_msc;
1250
1251 return TRUE;
1252
1253 blit_fallback:
1254 I830DRI2FallbackBlitSwap(draw, front, back);
1255 DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
1256 if (swap_info)
1257 i830_dri2_del_frame_event(swap_info);
1258 *target_msc = 0; /* offscreen, so zero out target vblank count */
1259 return TRUE;
1260 }
1261
gettime_us(void)1262 static uint64_t gettime_us(void)
1263 {
1264 struct timespec tv;
1265
1266 if (clock_gettime(CLOCK_MONOTONIC, &tv))
1267 return 0;
1268
1269 return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
1270 }
1271
1272 /*
1273 * Get current frame count and frame count timestamp, based on drawable's
1274 * crtc.
1275 */
1276 static int
I830DRI2GetMSC(DrawablePtr draw,CARD64 * ust,CARD64 * msc)1277 I830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
1278 {
1279 ScreenPtr screen = draw->pScreen;
1280 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1281 int ret;
1282 xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
1283
1284 /* Drawable not displayed, make up a *monotonic* value */
1285 if (crtc == NULL) {
1286 fail:
1287 *ust = gettime_us();
1288 *msc = 0;
1289 return TRUE;
1290 }
1291
1292 ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust);
1293 if (ret) {
1294 static int limit = 5;
1295 if (limit) {
1296 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1297 "%s:%d get vblank counter failed: %s\n",
1298 __FUNCTION__, __LINE__,
1299 strerror(errno));
1300 limit--;
1301 }
1302 goto fail;
1303 }
1304
1305 return TRUE;
1306 }
1307
1308 /*
1309 * Request a DRM event when the requested conditions will be satisfied.
1310 *
1311 * We need to handle the event and ask the server to wake up the client when
1312 * we receive it.
1313 */
1314 static int
I830DRI2ScheduleWaitMSC(ClientPtr client,DrawablePtr draw,CARD64 target_msc,CARD64 divisor,CARD64 remainder)1315 I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
1316 CARD64 divisor, CARD64 remainder)
1317 {
1318 ScreenPtr screen = draw->pScreen;
1319 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1320 intel_screen_private *intel = intel_get_screen_private(scrn);
1321 DRI2FrameEventPtr wait_info;
1322 drmVBlank vbl;
1323 int ret;
1324 xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
1325 int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
1326 CARD64 current_msc, current_ust, request_msc;
1327 uint32_t seq;
1328
1329 /* Drawable not visible, return immediately */
1330 if (pipe == -1)
1331 goto out_complete;
1332
1333 wait_info = calloc(1, sizeof(DRI2FrameEventRec));
1334 if (!wait_info)
1335 goto out_complete;
1336
1337 wait_info->intel = intel;
1338 wait_info->drawable_id = draw->id;
1339 wait_info->client = client;
1340 wait_info->type = DRI2_WAITMSC;
1341
1342 if (!i830_dri2_add_frame_event(wait_info)) {
1343 free(wait_info);
1344 goto out_complete;
1345 }
1346
1347 /* Get current count */
1348 ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust);
1349 if (ret)
1350 goto out_free;
1351
1352 /*
1353 * If divisor is zero, or current_msc is smaller than target_msc,
1354 * we just need to make sure target_msc passes before waking up the
1355 * client.
1356 */
1357 if (divisor == 0 || current_msc < target_msc) {
1358 /* If target_msc already reached or passed, set it to
1359 * current_msc to ensure we return a reasonable value back
1360 * to the caller. This keeps the client from continually
1361 * sending us MSC targets from the past by forcibly updating
1362 * their count on this call.
1363 */
1364 seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
1365 if (!seq)
1366 goto out_free;
1367
1368 if (current_msc >= target_msc)
1369 target_msc = current_msc;
1370 vbl.request.type =
1371 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
1372 vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc);
1373 vbl.request.signal = seq;
1374
1375 ret = drmWaitVBlank(intel->drmSubFD, &vbl);
1376 if (ret) {
1377 static int limit = 5;
1378 if (limit) {
1379 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1380 "%s:%d get vblank counter failed: %s\n",
1381 __FUNCTION__, __LINE__,
1382 strerror(errno));
1383 limit--;
1384 }
1385 intel_drm_abort_seq(intel->scrn, seq);
1386 goto out_complete;
1387 }
1388
1389 wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
1390 DRI2BlockClient(client, draw);
1391 return TRUE;
1392 }
1393
1394 /*
1395 * If we get here, target_msc has already passed or we don't have one,
1396 * so we queue an event that will satisfy the divisor/remainder equation.
1397 */
1398 vbl.request.type =
1399 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
1400
1401 request_msc = current_msc - (current_msc % divisor) +
1402 remainder;
1403 /*
1404 * If calculated remainder is larger than requested remainder,
1405 * it means we've passed the last point where
1406 * seq % divisor == remainder, so we need to wait for the next time
1407 * that will happen.
1408 */
1409 if ((current_msc % divisor) >= remainder)
1410 request_msc += divisor;
1411
1412 seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
1413 if (!seq)
1414 goto out_free;
1415
1416 vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc);
1417 vbl.request.signal = seq;
1418
1419 ret = drmWaitVBlank(intel->drmSubFD, &vbl);
1420 if (ret) {
1421 static int limit = 5;
1422 if (limit) {
1423 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1424 "%s:%d get vblank counter failed: %s\n",
1425 __FUNCTION__, __LINE__,
1426 strerror(errno));
1427 limit--;
1428 }
1429 intel_drm_abort_seq(intel->scrn, seq);
1430 goto out_complete;
1431 }
1432
1433 wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
1434 DRI2BlockClient(client, draw);
1435
1436 return TRUE;
1437
1438 out_free:
1439 i830_dri2_del_frame_event(wait_info);
1440 out_complete:
1441 DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
1442 return TRUE;
1443 }
1444
1445 static int dri2_server_generation;
1446 #endif
1447
has_i830_dri(void)1448 static int has_i830_dri(void)
1449 {
1450 return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0;
1451 }
1452
1453 static int
namecmp(const char * s1,const char * s2)1454 namecmp(const char *s1, const char *s2)
1455 {
1456 char c1, c2;
1457
1458 if (!s1 || *s1 == 0) {
1459 if (!s2 || *s2 == 0)
1460 return 0;
1461 else
1462 return 1;
1463 }
1464
1465 while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1466 s1++;
1467
1468 while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1469 s2++;
1470
1471 c1 = isupper(*s1) ? tolower(*s1) : *s1;
1472 c2 = isupper(*s2) ? tolower(*s2) : *s2;
1473 while (c1 == c2) {
1474 if (c1 == '\0')
1475 return 0;
1476
1477 s1++;
1478 while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1479 s1++;
1480
1481 s2++;
1482 while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1483 s2++;
1484
1485 c1 = isupper(*s1) ? tolower(*s1) : *s1;
1486 c2 = isupper(*s2) ? tolower(*s2) : *s2;
1487 }
1488
1489 return c1 - c2;
1490 }
1491
is_level(const char ** str)1492 static Bool is_level(const char **str)
1493 {
1494 const char *s = *str;
1495 char *end;
1496 unsigned val;
1497
1498 if (s == NULL || *s == '\0')
1499 return TRUE;
1500
1501 if (namecmp(s, "on") == 0)
1502 return TRUE;
1503 if (namecmp(s, "true") == 0)
1504 return TRUE;
1505 if (namecmp(s, "yes") == 0)
1506 return TRUE;
1507
1508 if (namecmp(s, "0") == 0)
1509 return TRUE;
1510 if (namecmp(s, "off") == 0)
1511 return TRUE;
1512 if (namecmp(s, "false") == 0)
1513 return TRUE;
1514 if (namecmp(s, "no") == 0)
1515 return TRUE;
1516
1517 val = strtoul(s, &end, 0);
1518 if (val && *end == '\0')
1519 return TRUE;
1520 if (val && *end == ':')
1521 *str = end + 1;
1522 return FALSE;
1523 }
1524
options_get_dri(intel_screen_private * intel)1525 static const char *options_get_dri(intel_screen_private *intel)
1526 {
1527 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
1528 return xf86GetOptValString(intel->Options, OPTION_DRI);
1529 #else
1530 return NULL;
1531 #endif
1532 }
1533
dri_driver_name(intel_screen_private * intel)1534 static const char *dri_driver_name(intel_screen_private *intel)
1535 {
1536 const char *s = options_get_dri(intel);
1537
1538 if (is_level(&s)) {
1539 if (INTEL_INFO(intel)->gen < 030)
1540 return has_i830_dri() ? "i830" : "i915";
1541 else if (INTEL_INFO(intel)->gen < 040)
1542 return "i915";
1543 else if (INTEL_INFO(intel)->gen < 0100)
1544 return "i965";
1545 else
1546 return "iris";
1547 }
1548
1549 return s;
1550 }
1551
I830DRI2ScreenInit(ScreenPtr screen)1552 Bool I830DRI2ScreenInit(ScreenPtr screen)
1553 {
1554 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1555 intel_screen_private *intel = intel_get_screen_private(scrn);
1556 DRI2InfoRec info;
1557 int dri2scr_major = 1;
1558 int dri2scr_minor = 0;
1559 #if DRI2INFOREC_VERSION >= 4
1560 const char *driverNames[2];
1561 #endif
1562
1563 if (intel->force_fallback) {
1564 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1565 "cannot enable DRI2 whilst forcing software fallbacks\n");
1566 return FALSE;
1567 }
1568
1569 if (xf86LoaderCheckSymbol("DRI2Version"))
1570 DRI2Version(&dri2scr_major, &dri2scr_minor);
1571
1572 if (dri2scr_minor < 1) {
1573 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1574 "DRI2 requires DRI2 module version 1.1.0 or later\n");
1575 return FALSE;
1576 }
1577
1578 #if HAS_DIXREGISTERPRIVATEKEY
1579 if (!dixRegisterPrivateKey(&i830_client_key, PRIVATE_CLIENT, sizeof(XID)))
1580 return FALSE;
1581 #else
1582 if (!dixRequestPrivate(&i830_client_key, sizeof(XID)))
1583 return FALSE;
1584 #endif
1585
1586
1587 #if DRI2INFOREC_VERSION >= 4
1588 if (serverGeneration != dri2_server_generation) {
1589 dri2_server_generation = serverGeneration;
1590 if (!i830_dri2_register_frame_event_resource_types()) {
1591 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1592 "Cannot register DRI2 frame event resources\n");
1593 return FALSE;
1594 }
1595 }
1596 #endif
1597
1598 intel->deviceName = drmGetDeviceNameFromFd(intel->drmSubFD);
1599 memset(&info, '\0', sizeof(info));
1600 info.fd = intel->drmSubFD;
1601 info.driverName = dri_driver_name(intel);
1602 info.deviceName = intel->deviceName;
1603
1604 #if DRI2INFOREC_VERSION == 1
1605 info.version = 1;
1606 info.CreateBuffers = I830DRI2CreateBuffers;
1607 info.DestroyBuffers = I830DRI2DestroyBuffers;
1608 #elif DRI2INFOREC_VERSION == 2
1609 /* The ABI between 2 and 3 was broken so we could get rid of
1610 * the multi-buffer alloc functions. Make sure we indicate the
1611 * right version so DRI2 can reject us if it's version 3 or above. */
1612 info.version = 2;
1613 info.CreateBuffer = I830DRI2CreateBuffer;
1614 info.DestroyBuffer = I830DRI2DestroyBuffer;
1615 #else
1616 info.version = 3;
1617 info.CreateBuffer = I830DRI2CreateBuffer;
1618 info.DestroyBuffer = I830DRI2DestroyBuffer;
1619 #endif
1620
1621 info.CopyRegion = I830DRI2CopyRegion;
1622 #if DRI2INFOREC_VERSION >= 4
1623 info.version = 4;
1624 info.ScheduleSwap = I830DRI2ScheduleSwap;
1625 info.GetMSC = I830DRI2GetMSC;
1626 info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC;
1627 info.numDrivers = 2;
1628 info.driverNames = driverNames;
1629 driverNames[0] = info.driverName;
1630 driverNames[1] = "va_gl";
1631 #endif
1632
1633 return DRI2ScreenInit(screen, &info);
1634 }
1635
I830DRI2CloseScreen(ScreenPtr screen)1636 void I830DRI2CloseScreen(ScreenPtr screen)
1637 {
1638 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1639 intel_screen_private *intel = intel_get_screen_private(scrn);
1640
1641 DRI2CloseScreen(screen);
1642 drmFree(intel->deviceName);
1643 }
1644