Bug Summary

File:present/present.c
Location:line 175, column 42
Description:Access to field 'pScreen' results in a dereference of a null pointer (loaded from variable 'crtc')

Annotated Source Code

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