Bug Summary

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