xref: /OK3568_Linux_fs/external/xserver/present/present_wnmd.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright © 2018 Roman Gilg
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 
29 /*
30  * Window flip mode
31  *
32  * Provides per-window flips. Flips can be processed on windows that
33  * have the same size as their parents, which they share their pixmap with.
34  *
35  * A flip still requires a copy currently, since the original pixmap needs
36  * to be updated with the new pixmap content. Just a flip of all windows
37  * to the new pixmap is diffcult, because the original pixmap might not be
38  * controlled by the Xserver.
39  *
40  */
41 
42 static void
43 present_wnmd_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
44 
45 static int
present_wnmd_queue_vblank(ScreenPtr screen,WindowPtr window,RRCrtcPtr crtc,uint64_t event_id,uint64_t msc)46 present_wnmd_queue_vblank(ScreenPtr screen,
47                           WindowPtr window,
48                           RRCrtcPtr crtc,
49                           uint64_t event_id,
50                           uint64_t msc)
51 {
52     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
53     return (*screen_priv->wnmd_info->queue_vblank) (window, crtc, event_id, msc);
54 }
55 
56 static void
present_wnmd_create_event_id(present_window_priv_ptr window_priv,present_vblank_ptr vblank)57 present_wnmd_create_event_id(present_window_priv_ptr window_priv, present_vblank_ptr vblank)
58 {
59     vblank->event_id = ++window_priv->event_id;
60 }
61 
62 static uint32_t
present_wnmd_query_capabilities(present_screen_priv_ptr screen_priv)63 present_wnmd_query_capabilities(present_screen_priv_ptr screen_priv)
64 {
65     return screen_priv->wnmd_info->capabilities;
66 }
67 
68 static RRCrtcPtr
present_wnmd_get_crtc(present_screen_priv_ptr screen_priv,WindowPtr window)69 present_wnmd_get_crtc(present_screen_priv_ptr screen_priv, WindowPtr window)
70 {
71     return (*screen_priv->wnmd_info->get_crtc)(window);
72 }
73 
74 static int
present_wnmd_get_ust_msc(ScreenPtr screen,WindowPtr window,uint64_t * ust,uint64_t * msc)75 present_wnmd_get_ust_msc(ScreenPtr screen, WindowPtr window, uint64_t *ust, uint64_t *msc)
76 {
77     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
78     return (*screen_priv->wnmd_info->get_ust_msc)(window, ust, msc);
79 }
80 
81 /*
82  * When the wait fence or previous flip is completed, it's time
83  * to re-try the request
84  */
85 static void
present_wnmd_re_execute(present_vblank_ptr vblank)86 present_wnmd_re_execute(present_vblank_ptr vblank)
87 {
88     uint64_t ust = 0, crtc_msc = 0;
89 
90     (void) present_wnmd_get_ust_msc(vblank->screen, vblank->window, &ust, &crtc_msc);
91     present_wnmd_execute(vblank, ust, crtc_msc);
92 }
93 
94 static void
present_wnmd_flip_try_ready(WindowPtr window)95 present_wnmd_flip_try_ready(WindowPtr window)
96 {
97     present_window_priv_ptr window_priv = present_window_priv(window);
98     present_vblank_ptr      vblank;
99 
100     xorg_list_for_each_entry(vblank, &window_priv->flip_queue, event_queue) {
101         if (vblank->queued) {
102             present_wnmd_re_execute(vblank);
103             return;
104         }
105     }
106 }
107 
108 static void
present_wnmd_free_idle_vblank(present_vblank_ptr vblank)109 present_wnmd_free_idle_vblank(present_vblank_ptr vblank)
110 {
111     present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
112     present_vblank_destroy(vblank);
113 }
114 
115 /*
116  * Free any left over idle vblanks
117  */
118 static void
present_wnmd_free_idle_vblanks(WindowPtr window)119 present_wnmd_free_idle_vblanks(WindowPtr window)
120 {
121     present_window_priv_ptr         window_priv = present_window_priv(window);
122     present_vblank_ptr              vblank, tmp;
123 
124     xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->idle_queue, event_queue) {
125         if (vblank->flip)
126             present_wnmd_free_idle_vblank(vblank);
127     }
128 
129     if (window_priv->flip_active) {
130         present_wnmd_free_idle_vblank(window_priv->flip_active);
131         window_priv->flip_active = NULL;
132     }
133 }
134 
135 static WindowPtr
present_wnmd_toplvl_pixmap_window(WindowPtr window)136 present_wnmd_toplvl_pixmap_window(WindowPtr window)
137 {
138     ScreenPtr       screen = window->drawable.pScreen;
139     PixmapPtr       pixmap = (*screen->GetWindowPixmap)(window);
140     WindowPtr       w = window;
141     WindowPtr       next_w;
142 
143     while(w->parent) {
144         next_w = w->parent;
145         if ( (*screen->GetWindowPixmap)(next_w) != pixmap) {
146             break;
147         }
148         w = next_w;
149     }
150     return w;
151 }
152 
153 void
present_wnmd_set_abort_flip(WindowPtr window)154 present_wnmd_set_abort_flip(WindowPtr window)
155 {
156     present_window_priv_ptr window_priv = present_window_priv(window);
157 
158     if (!window_priv->flip_pending->abort_flip) {
159         window_priv->flip_pending->abort_flip = TRUE;
160     }
161 }
162 
163 static void
present_wnmd_flips_stop(WindowPtr window)164 present_wnmd_flips_stop(WindowPtr window)
165 {
166     present_window_priv_ptr window_priv = present_window_priv(window);
167     present_screen_priv_ptr screen_priv = present_screen_priv(window->drawable.pScreen);
168 
169     assert (!window_priv->flip_pending);
170 
171     (*screen_priv->wnmd_info->flips_stop) (window);
172 
173     present_wnmd_free_idle_vblanks(window_priv->window);
174     present_wnmd_flip_try_ready(window_priv->window);
175 }
176 
177 static void
present_wnmd_flip_notify(present_vblank_ptr vblank,uint64_t ust,uint64_t crtc_msc)178 present_wnmd_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
179 {
180     WindowPtr                   window = vblank->window;
181     present_window_priv_ptr     window_priv = present_window_priv(window);
182 
183     DebugPresent(("\tn %" PRIu64 " %p %" PRIu64 " %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
184                   vblank->event_id, vblank, vblank->exec_msc, vblank->target_msc,
185                   vblank->pixmap ? vblank->pixmap->drawable.id : 0,
186                   vblank->window ? vblank->window->drawable.id : 0));
187 
188     assert (vblank == window_priv->flip_pending);
189 
190     xorg_list_del(&vblank->event_queue);
191 
192     if (window_priv->flip_active) {
193         if (window_priv->flip_active->flip_idler)
194             present_wnmd_free_idle_vblank(window_priv->flip_active);
195         else
196             /* Put the previous flip in the idle_queue and wait for further notice from DDX */
197             xorg_list_append(&window_priv->flip_active->event_queue, &window_priv->idle_queue);
198     }
199 
200     window_priv->flip_active = vblank;
201     window_priv->flip_pending = NULL;
202 
203     present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc);
204 
205     if (vblank->abort_flip)
206         present_wnmd_flips_stop(window);
207 
208     present_wnmd_flip_try_ready(window);
209 }
210 
211 void
present_wnmd_event_notify(WindowPtr window,uint64_t event_id,uint64_t ust,uint64_t msc)212 present_wnmd_event_notify(WindowPtr window, uint64_t event_id, uint64_t ust, uint64_t msc)
213 {
214     present_window_priv_ptr     window_priv = present_window_priv(window);
215     present_vblank_ptr          vblank;
216 
217     if (!window_priv)
218         return;
219     if (!event_id)
220         return;
221 
222     if (window_priv->flip_active && window_priv->flip_active->event_id == event_id) {
223         /* Notify for active flip, means it is allowed to become idle */
224         window_priv->flip_active->flip_idler = TRUE;
225         return;
226     }
227 
228     DebugPresent(("\te %" PRIu64 " ust %" PRIu64 " msc %" PRIu64 "\n", event_id, ust, msc));
229     xorg_list_for_each_entry(vblank, &window_priv->exec_queue, event_queue) {
230         if (event_id == vblank->event_id) {
231             present_wnmd_execute(vblank, ust, msc);
232             return;
233         }
234     }
235     xorg_list_for_each_entry(vblank, &window_priv->flip_queue, event_queue) {
236         if (vblank->event_id == event_id) {
237             if (vblank->queued) {
238                 present_wnmd_execute(vblank, ust, msc);
239             } else {
240                 assert(vblank->window);
241                 present_wnmd_flip_notify(vblank, ust, msc);
242             }
243             return;
244         }
245     }
246 
247     xorg_list_for_each_entry(vblank, &window_priv->idle_queue, event_queue) {
248         if (vblank->event_id == event_id) {
249             if (vblank->flip)
250                 present_wnmd_free_idle_vblank(vblank);
251             else
252                 /* Copies which were executed but need their completion event sent */
253                 present_execute_post(vblank, ust, msc);
254 
255             return;
256         }
257     }
258 }
259 
260 static Bool
present_wnmd_check_flip(RRCrtcPtr crtc,WindowPtr window,PixmapPtr pixmap,Bool sync_flip,RegionPtr valid,int16_t x_off,int16_t y_off,PresentFlipReason * reason)261 present_wnmd_check_flip(RRCrtcPtr           crtc,
262                         WindowPtr           window,
263                         PixmapPtr           pixmap,
264                         Bool                sync_flip,
265                         RegionPtr           valid,
266                         int16_t             x_off,
267                         int16_t             y_off,
268                         PresentFlipReason   *reason)
269 {
270     ScreenPtr               screen = window->drawable.pScreen;
271     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
272     WindowPtr               toplvl_window = present_wnmd_toplvl_pixmap_window(window);
273 
274     if (reason)
275         *reason = PRESENT_FLIP_REASON_UNKNOWN;
276 
277     if (!screen_priv)
278         return FALSE;
279 
280     if (!screen_priv->wnmd_info)
281         return FALSE;
282 
283     if (!crtc)
284         return FALSE;
285 
286     /* Check to see if the driver supports flips at all */
287     if (!screen_priv->wnmd_info->flip)
288         return FALSE;
289 
290     /* Source pixmap must align with window exactly */
291     if (x_off || y_off)
292         return FALSE;
293 
294     /* Valid area must contain window (for simplicity for now just never flip when one is set). */
295     if (valid)
296         return FALSE;
297 
298     /* Flip pixmap must have same dimensions as window */
299     if (window->drawable.width != pixmap->drawable.width ||
300             window->drawable.height != pixmap->drawable.height)
301         return FALSE;
302 
303     /* Window must be same region as toplevel window */
304     if ( !RegionEqual(&window->winSize, &toplvl_window->winSize) )
305         return FALSE;
306 
307     /* Can't flip if window clipped by children */
308     if (!RegionEqual(&window->clipList, &window->winSize))
309         return FALSE;
310 
311     /* Ask the driver for permission */
312     if (screen_priv->wnmd_info->check_flip2) {
313         if (!(*screen_priv->wnmd_info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) {
314             DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n",
315                           window->drawable.id, pixmap ? pixmap->drawable.id : 0));
316             return FALSE;
317         }
318     }
319 
320     return TRUE;
321 }
322 
323 /*
324  * 'window' is being reconfigured. Check to see if it is involved
325  * in flipping and clean up as necessary.
326  */
327 static void
present_wnmd_check_flip_window(WindowPtr window)328 present_wnmd_check_flip_window (WindowPtr window)
329 {
330     present_window_priv_ptr window_priv = present_window_priv(window);
331     present_vblank_ptr      flip_pending;
332     present_vblank_ptr      flip_active;
333     present_vblank_ptr      vblank;
334     PresentFlipReason       reason;
335 
336     /* If this window hasn't ever been used with Present, it can't be
337      * flipping
338      */
339     if (!window_priv)
340         return;
341 
342     flip_pending = window_priv->flip_pending;
343     flip_active = window_priv->flip_active;
344 
345     if (flip_pending) {
346         if (!present_wnmd_check_flip(flip_pending->crtc, flip_pending->window, flip_pending->pixmap,
347                                 flip_pending->sync_flip, flip_pending->valid, 0, 0, NULL))
348             present_wnmd_set_abort_flip(window);
349     } else if (flip_active) {
350         if (!present_wnmd_check_flip(flip_active->crtc, flip_active->window, flip_active->pixmap,
351                                      flip_active->sync_flip, flip_active->valid, 0, 0, NULL))
352             present_wnmd_flips_stop(window);
353     }
354 
355     /* Now check any queued vblanks */
356     xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
357         if (vblank->queued && vblank->flip &&
358                 !present_wnmd_check_flip(vblank->crtc, window, vblank->pixmap,
359                                          vblank->sync_flip, vblank->valid, 0, 0, &reason)) {
360             vblank->flip = FALSE;
361             vblank->reason = reason;
362         }
363     }
364 }
365 
366 static Bool
present_wnmd_flip(WindowPtr window,RRCrtcPtr crtc,uint64_t event_id,uint64_t target_msc,PixmapPtr pixmap,Bool sync_flip,RegionPtr damage)367 present_wnmd_flip(WindowPtr window,
368                   RRCrtcPtr crtc,
369                   uint64_t event_id,
370                   uint64_t target_msc,
371                   PixmapPtr pixmap,
372                   Bool sync_flip,
373                   RegionPtr damage)
374 {
375     ScreenPtr                   screen = window->drawable.pScreen;
376     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
377 
378     return (*screen_priv->wnmd_info->flip) (window,
379                                             crtc,
380                                             event_id,
381                                             target_msc,
382                                             pixmap,
383                                             sync_flip,
384                                             damage);
385 }
386 
387 static void
present_wnmd_cancel_flip(WindowPtr window)388 present_wnmd_cancel_flip(WindowPtr window)
389 {
390     present_window_priv_ptr window_priv = present_window_priv(window);
391 
392     if (window_priv->flip_pending)
393         present_wnmd_set_abort_flip(window);
394     else if (window_priv->flip_active)
395         present_wnmd_flips_stop(window);
396 }
397 
398 static Bool
present_wnmd_can_window_flip(WindowPtr window)399 present_wnmd_can_window_flip(WindowPtr window)
400 {
401     ScreenPtr                   screen = window->drawable.pScreen;
402     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
403     WindowPtr                   toplvl_window = present_wnmd_toplvl_pixmap_window(window);
404 
405     if (!screen_priv)
406         return FALSE;
407 
408     if (!screen_priv->wnmd_info)
409         return FALSE;
410 
411     /* Check to see if the driver supports flips at all */
412     if (!screen_priv->wnmd_info->flip)
413         return FALSE;
414 
415     /* Don't flip redirected windows */
416     if (window->redirectDraw != RedirectDrawNone)
417         return FALSE;
418 
419     /* Window must be same region as toplevel window */
420     if ( !RegionEqual(&window->winSize, &toplvl_window->winSize) )
421         return FALSE;
422 
423     return TRUE;
424 }
425 
426 /*
427  * Once the required MSC has been reached, execute the pending request.
428  *
429  * For requests to actually present something, either blt contents to
430  * the window pixmap or queue a window buffer swap on the backend.
431  *
432  * For requests to just get the current MSC/UST combo, skip that part and
433  * go straight to event delivery.
434  */
435 static void
present_wnmd_execute(present_vblank_ptr vblank,uint64_t ust,uint64_t crtc_msc)436 present_wnmd_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
437 {
438     WindowPtr               window = vblank->window;
439     present_window_priv_ptr window_priv = present_window_priv(window);
440 
441     if (present_execute_wait(vblank, crtc_msc))
442         return;
443 
444     if (vblank->flip && vblank->pixmap && vblank->window) {
445         if (window_priv->flip_pending) {
446             DebugPresent(("\tr %" PRIu64 " %p (pending %p)\n",
447                           vblank->event_id, vblank,
448                           window_priv->flip_pending));
449             xorg_list_del(&vblank->event_queue);
450             xorg_list_append(&vblank->event_queue, &window_priv->flip_queue);
451             vblank->flip_ready = TRUE;
452             return;
453         }
454     }
455 
456     xorg_list_del(&vblank->event_queue);
457     xorg_list_del(&vblank->window_list);
458     vblank->queued = FALSE;
459 
460     if (vblank->pixmap && vblank->window) {
461         ScreenPtr screen = window->drawable.pScreen;
462 
463         if (vblank->flip) {
464             RegionPtr damage;
465 
466             DebugPresent(("\tf %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
467                           vblank->event_id, vblank, crtc_msc,
468                           vblank->pixmap->drawable.id, vblank->window->drawable.id));
469 
470             /* Prepare to flip by placing it in the flip queue
471              */
472             xorg_list_add(&vblank->event_queue, &window_priv->flip_queue);
473 
474             /* Set update region as damaged */
475             if (vblank->update) {
476                 damage = RegionDuplicate(vblank->update);
477                 /* Translate update region to screen space */
478                 assert(vblank->x_off == 0 && vblank->y_off == 0);
479                 RegionTranslate(damage, window->drawable.x, window->drawable.y);
480                 RegionIntersect(damage, damage, &window->clipList);
481             } else
482                 damage = RegionDuplicate(&window->clipList);
483 
484             /* Try to flip - the vblank is now pending
485              */
486             window_priv->flip_pending = vblank;
487             // ask the driver
488             if (present_wnmd_flip(vblank->window, vblank->crtc, vblank->event_id,
489                                      vblank->target_msc, vblank->pixmap, vblank->sync_flip, damage)) {
490                 WindowPtr toplvl_window = present_wnmd_toplvl_pixmap_window(vblank->window);
491                 PixmapPtr old_pixmap = screen->GetWindowPixmap(window);
492 
493                 /* Replace window pixmap with flip pixmap */
494 #ifdef COMPOSITE
495                 vblank->pixmap->screen_x = old_pixmap->screen_x;
496                 vblank->pixmap->screen_y = old_pixmap->screen_y;
497 #endif
498                 present_set_tree_pixmap(toplvl_window, old_pixmap, vblank->pixmap);
499                 vblank->pixmap->refcnt++;
500                 dixDestroyPixmap(old_pixmap, old_pixmap->drawable.id);
501 
502                 /* Report damage */
503                 DamageDamageRegion(&vblank->window->drawable, damage);
504                 RegionDestroy(damage);
505                 return;
506             }
507 
508             xorg_list_del(&vblank->event_queue);
509             /* Flip failed. Clear the flip_pending field
510               */
511             window_priv->flip_pending = NULL;
512             vblank->flip = FALSE;
513         }
514         DebugPresent(("\tc %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
515                       vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
516 
517         present_wnmd_cancel_flip(window);
518 
519         present_execute_copy(vblank, crtc_msc);
520         assert(!vblank->queued);
521 
522         if (present_wnmd_queue_vblank(screen, window, vblank->crtc,
523                                       vblank->event_id, crtc_msc + 1)
524             == Success) {
525             xorg_list_add(&vblank->event_queue, &window_priv->idle_queue);
526             xorg_list_append(&vblank->window_list, &window_priv->vblank);
527 
528             return;
529         }
530     }
531 
532     present_execute_post(vblank, ust, crtc_msc);
533 }
534 
535 static uint64_t
present_wnmd_window_to_crtc_msc(WindowPtr window,RRCrtcPtr crtc,uint64_t window_msc,uint64_t new_msc)536 present_wnmd_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc, uint64_t new_msc)
537 {
538     present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
539 
540     if (crtc != window_priv->crtc) {
541         if (window_priv->crtc == PresentCrtcNeverSet) {
542             window_priv->msc_offset = 0;
543         } else {
544             /* The old CRTC may have been turned off, in which case
545              * we'll just use whatever previous MSC we'd seen from this CRTC
546              */
547 
548             window_priv->msc_offset += new_msc - window_priv->msc;
549         }
550         window_priv->crtc = crtc;
551     }
552 
553     return window_msc + window_priv->msc_offset;
554 }
555 
556 static int
present_wnmd_pixmap(WindowPtr window,PixmapPtr pixmap,CARD32 serial,RegionPtr valid,RegionPtr update,int16_t x_off,int16_t y_off,RRCrtcPtr target_crtc,SyncFence * wait_fence,SyncFence * idle_fence,uint32_t options,uint64_t window_msc,uint64_t divisor,uint64_t remainder,present_notify_ptr notifies,int num_notifies)557 present_wnmd_pixmap(WindowPtr window,
558                     PixmapPtr pixmap,
559                     CARD32 serial,
560                     RegionPtr valid,
561                     RegionPtr update,
562                     int16_t x_off,
563                     int16_t y_off,
564                     RRCrtcPtr target_crtc,
565                     SyncFence *wait_fence,
566                     SyncFence *idle_fence,
567                     uint32_t options,
568                     uint64_t window_msc,
569                     uint64_t divisor,
570                     uint64_t remainder,
571                     present_notify_ptr notifies,
572                     int num_notifies)
573 {
574     uint64_t                    ust = 0;
575     uint64_t                    target_msc;
576     uint64_t                    crtc_msc = 0;
577     int                         ret;
578     present_vblank_ptr          vblank, tmp;
579     ScreenPtr                   screen = window->drawable.pScreen;
580     present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
581     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
582 
583     if (!window_priv)
584         return BadAlloc;
585 
586     target_crtc = present_wnmd_get_crtc(screen_priv, window);
587 
588     ret = present_wnmd_get_ust_msc(screen, window, &ust, &crtc_msc);
589 
590     target_msc = present_wnmd_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
591 
592     if (ret == Success) {
593         /* Stash the current MSC away in case we need it later
594          */
595         window_priv->msc = crtc_msc;
596     }
597 
598     present_adjust_timings(options,
599                            &crtc_msc,
600                            &target_msc,
601                            divisor,
602                            remainder);
603 
604     /*
605      * Look for a matching presentation already on the list...
606      */
607 
608     if (!update && pixmap) {
609         xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
610 
611             if (!vblank->pixmap)
612                 continue;
613 
614             if (!vblank->queued)
615                 continue;
616 
617             if (vblank->target_msc != target_msc)
618                 continue;
619 
620             present_vblank_scrap(vblank);
621             if (vblank->flip_ready)
622                 present_wnmd_re_execute(vblank);
623         }
624     }
625 
626     vblank = present_vblank_create(window,
627                                    pixmap,
628                                    serial,
629                                    valid,
630                                    update,
631                                    x_off,
632                                    y_off,
633                                    target_crtc,
634                                    wait_fence,
635                                    idle_fence,
636                                    options,
637                                    &screen_priv->wnmd_info->capabilities,
638                                    notifies,
639                                    num_notifies,
640                                    target_msc,
641                                    crtc_msc);
642     if (!vblank)
643         return BadAlloc;
644 
645     /* WNMD presentations always complete (at least) one frame after they
646      * are executed
647      */
648     vblank->exec_msc = vblank->target_msc - 1;
649 
650     xorg_list_append(&vblank->event_queue, &window_priv->exec_queue);
651     vblank->queued = TRUE;
652     if (crtc_msc < vblank->exec_msc) {
653         if (present_wnmd_queue_vblank(screen, window, target_crtc, vblank->event_id, vblank->exec_msc) == Success) {
654             return Success;
655         }
656         DebugPresent(("present_queue_vblank failed\n"));
657     }
658 
659     present_wnmd_execute(vblank, ust, crtc_msc);
660     return Success;
661 }
662 
663 static void
present_wnmd_abort_vblank(ScreenPtr screen,WindowPtr window,RRCrtcPtr crtc,uint64_t event_id,uint64_t msc)664 present_wnmd_abort_vblank(ScreenPtr screen, WindowPtr window, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
665 {
666     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
667     present_window_priv_ptr window_priv = present_window_priv(window);
668     present_vblank_ptr      vblank;
669 
670     (*screen_priv->wnmd_info->abort_vblank) (window, crtc, event_id, msc);
671 
672     xorg_list_for_each_entry(vblank, &window_priv->exec_queue, event_queue) {
673         if (vblank->event_id == event_id) {
674             xorg_list_del(&vblank->event_queue);
675             vblank->queued = FALSE;
676             return;
677         }
678     }
679     xorg_list_for_each_entry(vblank, &window_priv->flip_queue, event_queue) {
680         if (vblank->event_id == event_id) {
681             xorg_list_del(&vblank->event_queue);
682             vblank->queued = FALSE;
683             return;
684         }
685     }
686 }
687 
688 static void
present_wnmd_flip_destroy(ScreenPtr screen)689 present_wnmd_flip_destroy(ScreenPtr screen)
690 {
691     /* Cleanup done on window destruction */
692 }
693 
694 static void
present_wnmd_flush(WindowPtr window)695 present_wnmd_flush(WindowPtr window)
696 {
697     ScreenPtr               screen = window->drawable.pScreen;
698     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
699 
700     (*screen_priv->wnmd_info->flush) (window);
701 }
702 
703 void
present_wnmd_init_mode_hooks(present_screen_priv_ptr screen_priv)704 present_wnmd_init_mode_hooks(present_screen_priv_ptr screen_priv)
705 {
706     screen_priv->query_capabilities =   &present_wnmd_query_capabilities;
707     screen_priv->get_crtc           =   &present_wnmd_get_crtc;
708 
709     screen_priv->check_flip         =   &present_wnmd_check_flip;
710     screen_priv->check_flip_window  =   &present_wnmd_check_flip_window;
711     screen_priv->can_window_flip    =   &present_wnmd_can_window_flip;
712 
713     screen_priv->present_pixmap     =   &present_wnmd_pixmap;
714     screen_priv->create_event_id    =   &present_wnmd_create_event_id;
715     screen_priv->queue_vblank       =   &present_wnmd_queue_vblank;
716     screen_priv->flush              =   &present_wnmd_flush;
717     screen_priv->re_execute         =   &present_wnmd_re_execute;
718 
719     screen_priv->abort_vblank       =   &present_wnmd_abort_vblank;
720     screen_priv->flip_destroy       =   &present_wnmd_flip_destroy;
721 }
722