Add patch that contain Mali fixes.
[deb_xorg-server.git] / present / present.c
1 /*
2 * Copyright © 2013 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23 #ifdef HAVE_XORG_CONFIG_H
24 #include <xorg-config.h>
25 #endif
26
27 #include "present_priv.h"
28 #include <gcstruct.h>
29 #include <misync.h>
30 #include <misyncstr.h>
31 #ifdef MONOTONIC_CLOCK
32 #include <time.h>
33 #endif
34
35 static uint64_t present_event_id;
36 static struct xorg_list present_exec_queue;
37 static struct xorg_list present_flip_queue;
38
39 #if 0
40 #define DebugPresent(x) ErrorF x
41 #else
42 #define DebugPresent(x)
43 #endif
44
45 /*
46 * Copies the update region from a pixmap to the target drawable
47 */
48 static void
49 present_copy_region(DrawablePtr drawable,
50 PixmapPtr pixmap,
51 RegionPtr update,
52 int16_t x_off,
53 int16_t y_off)
54 {
55 ScreenPtr screen = drawable->pScreen;
56 GCPtr gc;
57
58 gc = GetScratchGC(drawable->depth, screen);
59 if (update) {
60 ChangeGCVal changes[2];
61
62 changes[0].val = x_off;
63 changes[1].val = y_off;
64 ChangeGC(serverClient, gc,
65 GCClipXOrigin|GCClipYOrigin,
66 changes);
67 (*gc->funcs->ChangeClip)(gc, CT_REGION, update, 0);
68 }
69 ValidateGC(drawable, gc);
70 (*gc->ops->CopyArea)(&pixmap->drawable,
71 drawable,
72 gc,
73 0, 0,
74 pixmap->drawable.width, pixmap->drawable.height,
75 x_off, y_off);
76 if (update)
77 (*gc->funcs->ChangeClip)(gc, CT_NONE, NULL, 0);
78 FreeScratchGC(gc);
79 }
80
81 static Bool
82 present_check_flip(RRCrtcPtr crtc,
83 WindowPtr window,
84 PixmapPtr pixmap,
85 Bool sync_flip,
86 RegionPtr valid,
87 int16_t x_off,
88 int16_t y_off)
89 {
90 ScreenPtr screen = window->drawable.pScreen;
91 WindowPtr root = screen->root;
92 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
93
94 if (!screen_priv)
95 return FALSE;
96
97 if (!screen_priv->info)
98 return FALSE;
99
100 if (!crtc)
101 return FALSE;
102
103 /* Check to see if the driver supports flips at all */
104 if (!screen_priv->info->flip)
105 return FALSE;
106
107 /* Can't pend a flip while unflipping */
108 if (screen_priv->unflip_event_id) {
109 return FALSE;
110 }
111
112 /* Can't have two pending flips at the same time */
113 if (screen_priv->flip_pending) {
114 return FALSE;
115 }
116
117 /* Make sure the window hasn't been redirected with Composite */
118 if (screen->GetWindowPixmap(window) != screen->GetScreenPixmap(screen) &&
119 screen->GetWindowPixmap(window) != screen_priv->flip_pixmap)
120 return FALSE;
121
122 /* Check for full-screen window */
123 if (!RegionEqual(&window->clipList, &root->winSize)) {
124 return FALSE;
125 }
126
127 /* Source pixmap must align with window exactly */
128 if (x_off || y_off) {
129 return FALSE;
130 }
131
132 /* Make sure the area marked as valid fills the screen */
133 if (valid && !RegionEqual(valid, &root->winSize)) {
134 return FALSE;
135 }
136
137 /* Does the window match the pixmap exactly? */
138 if (window->drawable.x != 0 || window->drawable.y != 0 ||
139 #ifdef COMPOSITE
140 window->drawable.x != pixmap->screen_x || window->drawable.y != pixmap->screen_y ||
141 #endif
142 window->drawable.width != pixmap->drawable.width ||
143 window->drawable.height != pixmap->drawable.height) {
144 return FALSE;
145 }
146
147 /* Ask the driver for permission */
148 if (screen_priv->info->check_flip) {
149 if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
150 return FALSE;
151 }
152 }
153
154 return TRUE;
155 }
156
157 static Bool
158 present_flip(RRCrtcPtr crtc,
159 uint64_t event_id,
160 uint64_t target_msc,
161 PixmapPtr pixmap,
162 Bool sync_flip)
163 {
164 ScreenPtr screen = crtc->pScreen;
165 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
166
167 return (*screen_priv->info->flip) (crtc, event_id, target_msc, pixmap, sync_flip);
168 }
169
170 static void
171 present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_t ust, uint64_t crtc_msc)
172 {
173 int n;
174
175 if (vblank->window)
176 present_send_complete_notify(vblank->window, kind, mode, vblank->serial, ust, crtc_msc - vblank->msc_offset);
177 for (n = 0; n < vblank->num_notifies; n++) {
178 WindowPtr window = vblank->notifies[n].window;
179 CARD32 serial = vblank->notifies[n].serial;
180
181 if (window)
182 present_send_complete_notify(window, kind, mode, serial, ust, crtc_msc - vblank->msc_offset);
183 }
184 }
185
186 static void
187 present_pixmap_idle(PixmapPtr pixmap, WindowPtr window, CARD32 serial, struct present_fence *present_fence)
188 {
189 if (present_fence)
190 present_fence_set_triggered(present_fence);
191 if (window)
192 present_send_idle_notify(window, serial, pixmap, present_fence);
193 }
194
195 RRCrtcPtr
196 present_get_crtc(WindowPtr window)
197 {
198 ScreenPtr screen = window->drawable.pScreen;
199 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
200
201 if (!screen_priv)
202 return NULL;
203
204 if (!screen_priv->info)
205 return NULL;
206
207 return (*screen_priv->info->get_crtc)(window);
208 }
209
210 uint32_t
211 present_query_capabilities(RRCrtcPtr crtc)
212 {
213 present_screen_priv_ptr screen_priv;
214
215 if (!crtc)
216 return 0;
217
218 screen_priv = present_screen_priv(crtc->pScreen);
219
220 if (!screen_priv)
221 return 0;
222
223 if (!screen_priv->info)
224 return 0;
225
226 return screen_priv->info->capabilities;
227 }
228
229 static int
230 present_get_ust_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc)
231 {
232 ScreenPtr screen = window->drawable.pScreen;
233 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
234
235 if (crtc == NULL)
236 return present_fake_get_ust_msc(screen, ust, msc);
237 else
238 return (*screen_priv->info->get_ust_msc)(crtc, ust, msc);
239 }
240
241 static void
242 present_flush(WindowPtr window)
243 {
244 ScreenPtr screen = window->drawable.pScreen;
245 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
246
247 if (!screen_priv)
248 return;
249
250 if (!screen_priv->info)
251 return;
252
253 (*screen_priv->info->flush) (window);
254 }
255
256 static int
257 present_queue_vblank(ScreenPtr screen,
258 RRCrtcPtr crtc,
259 uint64_t event_id,
260 uint64_t msc)
261 {
262 Bool ret;
263
264 if (crtc == NULL)
265 ret = present_fake_queue_vblank(screen, event_id, msc);
266 else
267 {
268 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
269 ret = (*screen_priv->info->queue_vblank) (crtc, event_id, msc);
270 }
271 return ret;
272 }
273
274 static uint64_t
275 present_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc, uint64_t new_msc)
276 {
277 present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
278
279 if (crtc != window_priv->crtc) {
280 uint64_t old_ust, old_msc;
281
282 /* The old CRTC may have been turned off, in which case
283 * we'll just use whatever previous MSC we'd seen from this CRTC
284 */
285
286 if (present_get_ust_msc(window, window_priv->crtc, &old_ust, &old_msc) != Success)
287 old_msc = window_priv->msc;
288
289 window_priv->msc_offset += new_msc - old_msc;
290 window_priv->crtc = crtc;
291 }
292
293 return window_msc + window_priv->msc_offset;
294 }
295
296 static void
297 present_flip_idle(ScreenPtr screen)
298 {
299 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
300
301 if (screen_priv->flip_pixmap) {
302 present_pixmap_idle(screen_priv->flip_pixmap, screen_priv->flip_window,
303 screen_priv->flip_serial, screen_priv->flip_idle_fence);
304 if (screen_priv->flip_idle_fence)
305 present_fence_destroy(screen_priv->flip_idle_fence);
306 dixDestroyPixmap(screen_priv->flip_pixmap, screen_priv->flip_pixmap->drawable.id);
307 screen_priv->flip_crtc = NULL;
308 screen_priv->flip_window = NULL;
309 screen_priv->flip_serial = 0;
310 screen_priv->flip_pixmap = NULL;
311 screen_priv->flip_idle_fence = NULL;
312 }
313 }
314
315 struct pixmap_visit {
316 PixmapPtr old;
317 PixmapPtr new;
318 };
319
320 static int
321 present_set_tree_pixmap_visit(WindowPtr window, pointer data)
322 {
323 struct pixmap_visit *visit = data;
324 ScreenPtr screen = window->drawable.pScreen;
325
326 if ((*screen->GetWindowPixmap)(window) != visit->old)
327 return WT_DONTWALKCHILDREN;
328 (*screen->SetWindowPixmap)(window, visit->new);
329 return WT_WALKCHILDREN;
330 }
331
332 static void
333 present_set_tree_pixmap(WindowPtr window, PixmapPtr pixmap)
334 {
335 struct pixmap_visit visit;
336 ScreenPtr screen = window->drawable.pScreen;
337
338 visit.old = (*screen->GetWindowPixmap)(window);
339 visit.new = pixmap;
340 if (visit.old == visit.new)
341 return;
342 TraverseTree(window, present_set_tree_pixmap_visit, &visit);
343 }
344
345 static void
346 present_unflip(ScreenPtr screen)
347 {
348 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
349
350 assert (!screen_priv->unflip_event_id);
351 assert (!screen_priv->flip_pending);
352
353 if (screen_priv->flip_window)
354 present_set_tree_pixmap(screen_priv->flip_window,
355 (*screen->GetScreenPixmap)(screen));
356
357 present_set_tree_pixmap(screen->root, (*screen->GetScreenPixmap)(screen));
358
359 /* Update the screen pixmap with the current flip pixmap contents
360 */
361 if (screen_priv->flip_pixmap && screen_priv->flip_window) {
362 present_copy_region(&screen_priv->flip_window->drawable,
363 screen_priv->flip_pixmap,
364 NULL, 0, 0);
365 }
366 screen_priv->unflip_event_id = ++present_event_id;
367 DebugPresent(("u %lld\n", screen_priv->unflip_event_id));
368 (*screen_priv->info->unflip) (screen, screen_priv->unflip_event_id);
369 }
370
371 static void
372 present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
373
374 static void
375 present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
376 {
377 ScreenPtr screen = vblank->screen;
378 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
379
380 DebugPresent(("\tn %p %8lld: %08lx -> %08lx\n", vblank, vblank->target_msc,
381 vblank->pixmap ? vblank->pixmap->drawable.id : 0,
382 vblank->window->drawable.id));
383
384 assert (vblank == screen_priv->flip_pending);
385
386 present_flip_idle(screen);
387
388 xorg_list_del(&vblank->event_queue);
389
390 /* Transfer reference for pixmap and fence from vblank to screen_priv */
391 screen_priv->flip_crtc = vblank->crtc;
392 screen_priv->flip_window = vblank->window;
393 screen_priv->flip_serial = vblank->serial;
394 screen_priv->flip_pixmap = vblank->pixmap;
395 screen_priv->flip_idle_fence = vblank->idle_fence;
396
397 vblank->pixmap = NULL;
398 vblank->idle_fence = NULL;
399
400 screen_priv->flip_pending = NULL;
401
402 if (vblank->abort_flip)
403 present_unflip(screen);
404
405 present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc);
406 present_vblank_destroy(vblank);
407 }
408
409 void
410 present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc)
411 {
412 present_vblank_ptr vblank, tmp;
413 int s;
414
415 if (!event_id)
416 return;
417 DebugPresent(("\te %lld ust %lld msc %lld\n", event_id, ust, msc));
418 xorg_list_for_each_entry_safe(vblank, tmp, &present_exec_queue, event_queue) {
419 if (vblank->event_id == event_id) {
420 present_execute(vblank, ust, msc);
421 return;
422 }
423 }
424 xorg_list_for_each_entry_safe(vblank, tmp, &present_flip_queue, event_queue) {
425 if (vblank->event_id == event_id) {
426 present_flip_notify(vblank, ust, msc);
427 return;
428 }
429 }
430
431 for (s = 0; s < screenInfo.numScreens; s++) {
432 ScreenPtr screen = screenInfo.screens[s];
433 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
434
435 if (event_id == screen_priv->unflip_event_id) {
436 DebugPresent(("\tun %lld\n", event_id));
437 screen_priv->unflip_event_id = 0;
438 present_flip_idle(screen);
439 return;
440 }
441 }
442 }
443
444 /*
445 * 'window' is being reconfigured. Check to see if it is involved
446 * in flipping and clean up as necessary
447 */
448 void
449 present_check_flip_window (WindowPtr window)
450 {
451 ScreenPtr screen = window->drawable.pScreen;
452 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
453 present_window_priv_ptr window_priv = present_window_priv(window);
454 present_vblank_ptr flip_pending = screen_priv->flip_pending;
455 present_vblank_ptr vblank;
456
457 /* If this window hasn't ever been used with Present, it can't be
458 * flipping
459 */
460 if (!window_priv)
461 return;
462
463 if (screen_priv->unflip_event_id)
464 return;
465
466 if (flip_pending) {
467 /*
468 * Check pending flip
469 */
470 if (flip_pending->window == window) {
471 if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
472 flip_pending->sync_flip, NULL, 0, 0))
473 flip_pending->abort_flip = TRUE;
474 }
475 } else {
476 /*
477 * Check current flip
478 */
479 if (window == screen_priv->flip_window) {
480 if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, FALSE, NULL, 0, 0))
481 present_unflip(screen);
482 }
483 }
484
485 /* Now check any queued vblanks */
486 xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
487 if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, FALSE, NULL, 0, 0))
488 vblank->flip = FALSE;
489 }
490 }
491
492 /*
493 * Called when the wait fence is triggered; just gets the current msc/ust and
494 * calls present_execute again. That will re-check the fence and pend the
495 * request again if it's still not actually ready
496 */
497 static void
498 present_wait_fence_triggered(void *param)
499 {
500 present_vblank_ptr vblank = param;
501 WindowPtr window = vblank->window;
502 uint64_t ust = 0, crtc_msc = 0;
503
504 if (window) {
505 present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
506 if (window_priv)
507 (void) present_get_ust_msc(window, window_priv->crtc, &ust, &crtc_msc);
508 }
509 present_execute(vblank, ust, crtc_msc);
510 }
511
512 /*
513 * Once the required MSC has been reached, execute the pending request.
514 *
515 * For requests to actually present something, either blt contents to
516 * the screen or queue a frame buffer swap.
517 *
518 * For requests to just get the current MSC/UST combo, skip that part and
519 * go straight to event delivery
520 */
521
522 static void
523 present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
524 {
525 WindowPtr window = vblank->window;
526 ScreenPtr screen = window->drawable.pScreen;
527 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
528 uint8_t mode;
529
530 if (vblank->wait_fence) {
531 if (!present_fence_check_triggered(vblank->wait_fence)) {
532 present_fence_set_callback(vblank->wait_fence, present_wait_fence_triggered, vblank);
533 return;
534 }
535 }
536
537 xorg_list_del(&vblank->event_queue);
538 vblank->queued = FALSE;
539
540 if (vblank->pixmap && vblank->window) {
541
542 if (vblank->flip && screen_priv->flip_pending == NULL && !screen_priv->unflip_event_id) {
543
544 DebugPresent(("\tf %p %8lld: %08lx -> %08lx\n", vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
545 /* Prepare to flip by placing it in the flip queue and
546 * and sticking it into the flip_pending field
547 */
548 screen_priv->flip_pending = vblank;
549
550 xorg_list_add(&vblank->event_queue, &present_flip_queue);
551 /* Try to flip
552 */
553 if (present_flip(vblank->crtc, vblank->event_id, vblank->target_msc, vblank->pixmap, vblank->sync_flip)) {
554 RegionPtr damage;
555
556 /* Fix window pixmaps:
557 * 1) Restore previous flip window pixmap
558 * 2) Set current flip window pixmap to the new pixmap
559 */
560 if (screen_priv->flip_window && screen_priv->flip_window != window)
561 present_set_tree_pixmap(screen_priv->flip_window,
562 (*screen->GetScreenPixmap)(screen));
563 present_set_tree_pixmap(vblank->window, vblank->pixmap);
564 present_set_tree_pixmap(screen->root, vblank->pixmap);
565
566 /* Report update region as damaged
567 */
568 if (vblank->update) {
569 damage = vblank->update;
570 RegionIntersect(damage, damage, &window->clipList);
571 } else
572 damage = &window->clipList;
573
574 DamageDamageRegion(&vblank->window->drawable, damage);
575 return;
576 }
577
578 xorg_list_del(&vblank->event_queue);
579 /* Oops, flip failed. Clear the flip_pending field
580 */
581 screen_priv->flip_pending = NULL;
582 vblank->flip = FALSE;
583 }
584 DebugPresent(("\tc %p %8lld: %08lx -> %08lx\n", vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
585 if (screen_priv->flip_pending) {
586
587 /* Check pending flip
588 */
589 if (window == screen_priv->flip_pending->window)
590 screen_priv->flip_pending->abort_flip = TRUE;
591 } else if (!screen_priv->unflip_event_id) {
592
593 /* Check current flip
594 */
595 if (window == screen_priv->flip_window)
596 present_unflip(screen);
597 }
598 present_copy_region(&window->drawable, vblank->pixmap, vblank->update, vblank->x_off, vblank->y_off);
599
600 /* present_copy_region sticks the region into a scratch GC,
601 * which is then freed, freeing the region
602 */
603 vblank->update = NULL;
604 present_flush(window);
605
606 present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
607 }
608
609 /* Compute correct CompleteMode
610 */
611 if (vblank->kind == PresentCompleteKindPixmap) {
612 if (vblank->pixmap && vblank->window)
613 mode = PresentCompleteModeCopy;
614 else
615 mode = PresentCompleteModeSkip;
616 }
617 else
618 mode = PresentCompleteModeCopy;
619
620
621 present_vblank_notify(vblank, vblank->kind, mode, ust, crtc_msc);
622 present_vblank_destroy(vblank);
623 }
624
625 int
626 present_pixmap(WindowPtr window,
627 PixmapPtr pixmap,
628 CARD32 serial,
629 RegionPtr valid,
630 RegionPtr update,
631 int16_t x_off,
632 int16_t y_off,
633 RRCrtcPtr target_crtc,
634 SyncFence *wait_fence,
635 SyncFence *idle_fence,
636 uint32_t options,
637 uint64_t window_msc,
638 uint64_t divisor,
639 uint64_t remainder,
640 present_notify_ptr notifies,
641 int num_notifies)
642 {
643 uint64_t ust;
644 uint64_t target_msc;
645 uint64_t crtc_msc;
646 int ret;
647 present_vblank_ptr vblank;
648 ScreenPtr screen = window->drawable.pScreen;
649 present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
650 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
651
652 if (!window_priv)
653 return BadAlloc;
654
655 if (!screen_priv || !screen_priv->info)
656 target_crtc = NULL;
657 else if (!target_crtc) {
658 /* Update the CRTC if we have a pixmap or we don't have a CRTC
659 */
660 if (!pixmap)
661 target_crtc = window_priv->crtc;
662
663 if (!target_crtc)
664 target_crtc = present_get_crtc(window);
665 }
666
667 present_get_ust_msc(window, target_crtc, &ust, &crtc_msc);
668
669 target_msc = present_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
670
671 /* Stash the current MSC away in case we need it later
672 */
673 window_priv->msc = crtc_msc;
674
675 /* Adjust target_msc to match modulus
676 */
677 if (crtc_msc >= target_msc) {
678 if (divisor != 0) {
679 target_msc = crtc_msc - (crtc_msc % divisor) + remainder;
680 if (options & PresentOptionAsync) {
681 if (target_msc < crtc_msc)
682 target_msc += divisor;
683 } else {
684 if (target_msc <= crtc_msc)
685 target_msc += divisor;
686 }
687 } else {
688 target_msc = crtc_msc;
689 if (!(options & PresentOptionAsync))
690 target_msc++;
691 }
692 }
693
694 /*
695 * Look for a matching presentation already on the list and
696 * don't bother doing the previous one if this one will overwrite it
697 * in the same frame
698 */
699
700 if (!update) {
701 xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
702
703 if (!vblank->pixmap)
704 continue;
705
706 if (!vblank->queued)
707 continue;
708
709 if (vblank->crtc != target_crtc || vblank->target_msc != target_msc)
710 continue;
711
712 DebugPresent(("\tx %lld %p %8lld: %08lx -> %08lx (crtc %p)\n",
713 vblank->event_id, vblank, target_msc,
714 vblank->pixmap->drawable.id, vblank->window->drawable.id,
715 vblank->crtc));
716
717 present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
718 present_fence_destroy(vblank->idle_fence);
719 dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
720
721 vblank->pixmap = NULL;
722 vblank->idle_fence = NULL;
723 }
724 }
725
726 vblank = calloc (1, sizeof (present_vblank_rec));
727 if (!vblank)
728 return BadAlloc;
729
730 xorg_list_append(&vblank->window_list, &window_priv->vblank);
731 xorg_list_init(&vblank->event_queue);
732
733 vblank->screen = screen;
734 vblank->window = window;
735 vblank->pixmap = pixmap;
736 vblank->event_id = ++present_event_id;
737 if (pixmap) {
738 vblank->kind = PresentCompleteKindPixmap;
739 pixmap->refcnt++;
740 } else
741 vblank->kind = PresentCompleteKindNotifyMSC;
742
743 vblank->serial = serial;
744
745 if (valid) {
746 vblank->valid = RegionDuplicate(valid);
747 if (!vblank->valid)
748 goto no_mem;
749 }
750 if (update) {
751 vblank->update = RegionDuplicate(update);
752 if (!vblank->update)
753 goto no_mem;
754 }
755
756 vblank->x_off = x_off;
757 vblank->y_off = y_off;
758 vblank->target_msc = target_msc;
759 vblank->crtc = target_crtc;
760 vblank->msc_offset = window_priv->msc_offset;
761 vblank->notifies = notifies;
762 vblank->num_notifies = num_notifies;
763
764 if (!screen_priv->info || !(screen_priv->info->capabilities & PresentCapabilityAsync))
765 vblank->sync_flip = TRUE;
766
767 if (pixmap && present_check_flip (target_crtc, window, pixmap, vblank->sync_flip, valid, x_off, y_off)) {
768 vblank->flip = TRUE;
769 if (vblank->sync_flip)
770 target_msc--;
771 }
772
773 if (wait_fence) {
774 vblank->wait_fence = present_fence_create(wait_fence);
775 if (!vblank->wait_fence)
776 goto no_mem;
777 }
778
779 if (idle_fence) {
780 vblank->idle_fence = present_fence_create(idle_fence);
781 if (!vblank->idle_fence)
782 goto no_mem;
783 }
784
785 if (pixmap)
786 DebugPresent(("q %lld %p %8lld: %08lx -> %08lx (crtc %p)\n",
787 vblank->event_id, vblank, target_msc,
788 vblank->pixmap->drawable.id, vblank->window->drawable.id,
789 target_crtc));
790
791 xorg_list_add(&vblank->event_queue, &present_exec_queue);
792 vblank->queued = TRUE;
793 if (target_msc >= crtc_msc) {
794 ret = present_queue_vblank(screen, target_crtc, vblank->event_id, target_msc);
795 if (ret != Success) {
796 xorg_list_del(&vblank->event_queue);
797 vblank->queued = FALSE;
798 goto failure;
799 }
800 } else
801 present_execute(vblank, ust, crtc_msc);
802
803 return Success;
804
805 no_mem:
806 ret = BadAlloc;
807 failure:
808 vblank->notifies = NULL;
809 present_vblank_destroy(vblank);
810 return ret;
811 }
812
813 void
814 present_abort_vblank(ScreenPtr screen, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
815 {
816 present_vblank_ptr vblank, tmp;
817
818 if (crtc == NULL)
819 present_fake_abort_vblank(screen, event_id, msc);
820 else
821 {
822 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
823
824 (*screen_priv->info->abort_vblank) (crtc, event_id, msc);
825 }
826
827 xorg_list_for_each_entry_safe(vblank, tmp, &present_exec_queue, event_queue) {
828 if (vblank->event_id == event_id) {
829 xorg_list_del(&vblank->event_queue);
830 vblank->queued = FALSE;
831 return;
832 }
833 }
834 xorg_list_for_each_entry_safe(vblank, tmp, &present_flip_queue, event_queue) {
835 if (vblank->event_id == event_id) {
836 xorg_list_del(&vblank->event_queue);
837 return;
838 }
839 }
840 }
841
842 int
843 present_notify_msc(WindowPtr window,
844 CARD32 serial,
845 uint64_t target_msc,
846 uint64_t divisor,
847 uint64_t remainder)
848 {
849 return present_pixmap(window,
850 NULL,
851 serial,
852 NULL, NULL,
853 0, 0,
854 NULL,
855 NULL, NULL,
856 0,
857 target_msc, divisor, remainder, NULL, 0);
858 }
859
860 void
861 present_flip_destroy(ScreenPtr screen)
862 {
863 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
864
865 /* XXX this needs to be synchronous for server reset */
866
867 /* Do the actual cleanup once the flip has been performed by the hardware */
868 if (screen_priv->flip_pending)
869 screen_priv->flip_pending->abort_flip = TRUE;
870 }
871
872 void
873 present_vblank_destroy(present_vblank_ptr vblank)
874 {
875 /* Remove vblank from window and screen lists */
876 xorg_list_del(&vblank->window_list);
877
878 DebugPresent(("\td %p %8lld: %08lx -> %08lx\n", vblank, vblank->target_msc,
879 vblank->pixmap ? vblank->pixmap->drawable.id : 0,
880 vblank->window->drawable.id));
881
882 /* Drop pixmap reference */
883 if (vblank->pixmap)
884 dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
885
886 /* Free regions */
887 if (vblank->valid)
888 RegionDestroy(vblank->valid);
889 if (vblank->update)
890 RegionDestroy(vblank->update);
891
892 if (vblank->wait_fence)
893 present_fence_destroy(vblank->wait_fence);
894
895 if (vblank->idle_fence)
896 present_fence_destroy(vblank->idle_fence);
897
898 if (vblank->notifies)
899 present_destroy_notifies(vblank->notifies, vblank->num_notifies);
900
901 free(vblank);
902 }
903
904 Bool
905 present_init(void)
906 {
907 xorg_list_init(&present_exec_queue);
908 xorg_list_init(&present_flip_queue);
909 present_fake_queue_init();
910 return TRUE;
911 }