"Fossies" - the Fresh Open Source Software Archive

Member "xorg-server-1.20.8/hw/xwayland/xwayland-present.c" (29 Mar 2020, 17481 Bytes) of package /linux/misc/xorg-server-1.20.8.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "xwayland-present.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.20.7_vs_1.20.8.

    1 /*
    2  * Copyright © 2018 Roman Gilg
    3  *
    4  * Permission to use, copy, modify, distribute, and sell this software
    5  * and its documentation for any purpose is hereby granted without
    6  * fee, provided that the above copyright notice appear in all copies
    7  * and that both that copyright notice and this permission notice
    8  * appear in supporting documentation, and that the name of the
    9  * copyright holders not be used in advertising or publicity
   10  * pertaining to distribution of the software without specific,
   11  * written prior permission.  The copyright holders make no
   12  * representations about the suitability of this software for any
   13  * purpose.  It is provided "as is" without express or implied
   14  * warranty.
   15  *
   16  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
   17  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
   18  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
   19  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
   21  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   22  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   23  * SOFTWARE.
   24  */
   25 
   26 #include "xwayland.h"
   27 #include "glamor.h"
   28 
   29 #include <present.h>
   30 
   31 /*
   32  * When not flipping let Present copy with 60fps.
   33  * When flipping wait on frame_callback, otherwise
   34  * the surface is not visible, in this case update
   35  * with long interval.
   36  */
   37 #define TIMER_LEN_COPY      17  // ~60fps
   38 #define TIMER_LEN_FLIP    1000  // 1fps
   39 
   40 static DevPrivateKeyRec xwl_present_window_private_key;
   41 
   42 static struct xwl_present_window *
   43 xwl_present_window_priv(WindowPtr window)
   44 {
   45     return dixGetPrivate(&window->devPrivates,
   46                          &xwl_present_window_private_key);
   47 }
   48 
   49 static struct xwl_present_window *
   50 xwl_present_window_get_priv(WindowPtr window)
   51 {
   52     struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
   53 
   54     if (xwl_present_window == NULL) {
   55         xwl_present_window = calloc (1, sizeof (struct xwl_present_window));
   56         if (!xwl_present_window)
   57             return NULL;
   58 
   59         xwl_present_window->window = window;
   60         xwl_present_window->msc = 1;
   61         xwl_present_window->ust = GetTimeInMicros();
   62 
   63         xorg_list_init(&xwl_present_window->frame_callback_list);
   64         xorg_list_init(&xwl_present_window->event_list);
   65         xorg_list_init(&xwl_present_window->release_queue);
   66 
   67         dixSetPrivate(&window->devPrivates,
   68                       &xwl_present_window_private_key,
   69                       xwl_present_window);
   70     }
   71 
   72     return xwl_present_window;
   73 }
   74 
   75 static void
   76 xwl_present_free_timer(struct xwl_present_window *xwl_present_window)
   77 {
   78     TimerFree(xwl_present_window->frame_timer);
   79     xwl_present_window->frame_timer = NULL;
   80 }
   81 
   82 static CARD32
   83 xwl_present_timer_callback(OsTimerPtr timer,
   84                            CARD32 time,
   85                            void *arg);
   86 
   87 static inline Bool
   88 xwl_present_has_events(struct xwl_present_window *xwl_present_window)
   89 {
   90     return !!xwl_present_window->sync_flip ||
   91            !xorg_list_is_empty(&xwl_present_window->event_list);
   92 }
   93 
   94 static void
   95 xwl_present_reset_timer(struct xwl_present_window *xwl_present_window)
   96 {
   97     if (xwl_present_has_events(xwl_present_window)) {
   98         CARD32 timeout;
   99 
  100         if (!xorg_list_is_empty(&xwl_present_window->frame_callback_list))
  101             timeout = TIMER_LEN_FLIP;
  102         else
  103             timeout = TIMER_LEN_COPY;
  104 
  105         xwl_present_window->frame_timer = TimerSet(xwl_present_window->frame_timer,
  106                                                    0, timeout,
  107                                                    &xwl_present_timer_callback,
  108                                                    xwl_present_window);
  109     } else {
  110         xwl_present_free_timer(xwl_present_window);
  111     }
  112 }
  113 
  114 void
  115 xwl_present_cleanup(WindowPtr window)
  116 {
  117     struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
  118     struct xwl_present_event *event, *tmp;
  119 
  120     if (!xwl_present_window)
  121         return;
  122 
  123     xorg_list_del(&xwl_present_window->frame_callback_list);
  124 
  125     if (xwl_present_window->sync_callback) {
  126         wl_callback_destroy(xwl_present_window->sync_callback);
  127         xwl_present_window->sync_callback = NULL;
  128     }
  129 
  130     /* Clear remaining events */
  131     xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->event_list, list) {
  132         xorg_list_del(&event->list);
  133         free(event);
  134     }
  135 
  136     /* Clear remaining buffer releases and inform Present about free ressources */
  137     event = xwl_present_window->sync_flip;
  138     xwl_present_window->sync_flip = NULL;
  139     if (event) {
  140         if (event->buffer_released) {
  141             free(event);
  142         } else {
  143             event->pending = FALSE;
  144             event->abort = TRUE;
  145         }
  146     }
  147     xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->release_queue, list) {
  148         xorg_list_del(&event->list);
  149         event->abort = TRUE;
  150     }
  151 
  152     /* Clear timer */
  153     xwl_present_free_timer(xwl_present_window);
  154 
  155     /* Remove from privates so we don't try to access it later */
  156     dixSetPrivate(&window->devPrivates,
  157                   &xwl_present_window_private_key,
  158                   NULL);
  159 
  160     free(xwl_present_window);
  161 }
  162 
  163 static void
  164 xwl_present_free_event(struct xwl_present_event *event)
  165 {
  166     xorg_list_del(&event->list);
  167     free(event);
  168 }
  169 
  170 static void
  171 xwl_present_buffer_release(void *data, struct wl_buffer *buffer)
  172 {
  173     struct xwl_present_event *event = data;
  174     if (!event)
  175         return;
  176 
  177     wl_buffer_set_user_data(buffer, NULL);
  178     event->buffer_released = TRUE;
  179 
  180     if (event->abort) {
  181         if (!event->pending)
  182             xwl_present_free_event(event);
  183         return;
  184     }
  185 
  186     if (!event->pending) {
  187         present_wnmd_event_notify(event->xwl_present_window->window,
  188                                   event->event_id,
  189                                   event->xwl_present_window->ust,
  190                                   event->xwl_present_window->msc);
  191         xwl_present_free_event(event);
  192     }
  193 }
  194 
  195 static const struct wl_buffer_listener xwl_present_release_listener = {
  196     xwl_present_buffer_release
  197 };
  198 
  199 static void
  200 xwl_present_msc_bump(struct xwl_present_window *xwl_present_window)
  201 {
  202     uint64_t msc = ++xwl_present_window->msc;
  203     struct xwl_present_event    *event, *tmp;
  204 
  205     xwl_present_window->ust = GetTimeInMicros();
  206 
  207     event = xwl_present_window->sync_flip;
  208     xwl_present_window->sync_flip = NULL;
  209     if (event) {
  210         event->pending = FALSE;
  211 
  212         present_wnmd_event_notify(xwl_present_window->window, event->event_id,
  213                                   xwl_present_window->ust, msc);
  214 
  215         if (event->buffer_released) {
  216             /* If the buffer was already released, clean up now */
  217             present_wnmd_event_notify(xwl_present_window->window, event->event_id,
  218                                       xwl_present_window->ust, msc);
  219             free(event);
  220         } else {
  221             xorg_list_add(&event->list, &xwl_present_window->release_queue);
  222         }
  223     }
  224 
  225     xorg_list_for_each_entry_safe(event, tmp,
  226                                   &xwl_present_window->event_list,
  227                                   list) {
  228         if (event->target_msc <= msc) {
  229             present_wnmd_event_notify(xwl_present_window->window,
  230                                       event->event_id,
  231                                       xwl_present_window->ust,
  232                                       msc);
  233             xwl_present_free_event(event);
  234         }
  235     }
  236 }
  237 
  238 CARD32
  239 xwl_present_timer_callback(OsTimerPtr timer,
  240                            CARD32 time,
  241                            void *arg)
  242 {
  243     struct xwl_present_window *xwl_present_window = arg;
  244 
  245     /* If we were expecting a frame callback for this window, it didn't arrive
  246      * in a second. Stop listening to it to avoid double-bumping the MSC
  247      */
  248     xorg_list_del(&xwl_present_window->frame_callback_list);
  249 
  250     xwl_present_msc_bump(xwl_present_window);
  251     xwl_present_reset_timer(xwl_present_window);
  252 
  253     return 0;
  254 }
  255 
  256 void
  257 xwl_present_frame_callback(struct xwl_present_window *xwl_present_window)
  258 {
  259     xorg_list_del(&xwl_present_window->frame_callback_list);
  260 
  261     xwl_present_msc_bump(xwl_present_window);
  262 
  263     /* we do not need the timer anymore for this frame,
  264      * reset it for potentially the next one
  265      */
  266     xwl_present_reset_timer(xwl_present_window);
  267 }
  268 
  269 static void
  270 xwl_present_sync_callback(void *data,
  271                struct wl_callback *callback,
  272                uint32_t time)
  273 {
  274     struct xwl_present_event *event = data;
  275     struct xwl_present_window *xwl_present_window = event->xwl_present_window;
  276 
  277     wl_callback_destroy(xwl_present_window->sync_callback);
  278     xwl_present_window->sync_callback = NULL;
  279 
  280     event->pending = FALSE;
  281 
  282     if (event->abort) {
  283         /* Event might have been aborted */
  284         if (event->buffer_released)
  285             /* Buffer was already released, cleanup now */
  286             xwl_present_free_event(event);
  287         return;
  288     }
  289 
  290     present_wnmd_event_notify(xwl_present_window->window,
  291                               event->event_id,
  292                               xwl_present_window->ust,
  293                               xwl_present_window->msc);
  294 
  295     if (event->buffer_released) {
  296         /* If the buffer was already released, send the event now again */
  297         present_wnmd_event_notify(xwl_present_window->window,
  298                                   event->event_id,
  299                                   xwl_present_window->ust,
  300                                   xwl_present_window->msc);
  301         xwl_present_free_event(event);
  302     }
  303 }
  304 
  305 static const struct wl_callback_listener xwl_present_sync_listener = {
  306     xwl_present_sync_callback
  307 };
  308 
  309 static RRCrtcPtr
  310 xwl_present_get_crtc(WindowPtr present_window)
  311 {
  312     struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
  313     rrScrPrivPtr rr_private;
  314 
  315     if (xwl_present_window == NULL)
  316         return NULL;
  317 
  318     rr_private = rrGetScrPriv(present_window->drawable.pScreen);
  319 
  320     if (rr_private->numCrtcs == 0)
  321         return NULL;
  322 
  323     return rr_private->crtcs[0];
  324 }
  325 
  326 static int
  327 xwl_present_get_ust_msc(WindowPtr present_window, uint64_t *ust, uint64_t *msc)
  328 {
  329     struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
  330     if (!xwl_present_window)
  331         return BadAlloc;
  332 
  333     *ust = xwl_present_window->ust;
  334     *msc = xwl_present_window->msc;
  335 
  336     return Success;
  337 }
  338 
  339 /*
  340  * Queue an event to report back to the Present extension when the specified
  341  * MSC has past
  342  */
  343 static int
  344 xwl_present_queue_vblank(WindowPtr present_window,
  345                          RRCrtcPtr crtc,
  346                          uint64_t event_id,
  347                          uint64_t msc)
  348 {
  349     struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
  350     struct xwl_window *xwl_window = xwl_window_from_window(present_window);
  351     struct xwl_present_event *event;
  352 
  353     event = malloc(sizeof *event);
  354     if (!event)
  355         return BadAlloc;
  356 
  357     event->event_id = event_id;
  358     event->xwl_present_window = xwl_present_window;
  359     event->target_msc = msc;
  360 
  361     xorg_list_append(&event->list, &xwl_present_window->event_list);
  362 
  363     /* If there's a pending frame callback, use that */
  364     if (xwl_window && xwl_window->frame_callback &&
  365         xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
  366         xorg_list_add(&xwl_present_window->frame_callback_list,
  367                       &xwl_window->frame_callback_list);
  368     }
  369 
  370     if ((xwl_window && xwl_window->frame_callback) ||
  371         !xwl_present_window->frame_timer)
  372         xwl_present_reset_timer(xwl_present_window);
  373 
  374     return Success;
  375 }
  376 
  377 /*
  378  * Remove a pending vblank event so that it is not reported
  379  * to the extension
  380  */
  381 static void
  382 xwl_present_abort_vblank(WindowPtr present_window,
  383                          RRCrtcPtr crtc,
  384                          uint64_t event_id,
  385                          uint64_t msc)
  386 {
  387     struct xwl_present_window *xwl_present_window = xwl_present_window_priv(present_window);
  388     struct xwl_present_event *event, *tmp;
  389 
  390     if (!xwl_present_window)
  391         return;
  392 
  393     xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->event_list, list) {
  394         if (event->event_id == event_id) {
  395             xorg_list_del(&event->list);
  396             free(event);
  397             return;
  398         }
  399     }
  400 
  401     xorg_list_for_each_entry(event, &xwl_present_window->release_queue, list) {
  402         if (event->event_id == event_id) {
  403             event->abort = TRUE;
  404             return;
  405         }
  406     }
  407 }
  408 
  409 static void
  410 xwl_present_flush(WindowPtr window)
  411 {
  412     glamor_block_handler(window->drawable.pScreen);
  413 }
  414 
  415 static Bool
  416 xwl_present_check_flip2(RRCrtcPtr crtc,
  417                         WindowPtr present_window,
  418                         PixmapPtr pixmap,
  419                         Bool sync_flip,
  420                         PresentFlipReason *reason)
  421 {
  422     struct xwl_window *xwl_window = xwl_window_from_window(present_window);
  423 
  424     if (!xwl_window)
  425         return FALSE;
  426 
  427     /*
  428      * We currently only allow flips of windows, that have the same
  429      * dimensions as their xwl_window parent window. For the case of
  430      * different sizes subsurfaces are presumably the way forward.
  431      */
  432     if (!RegionEqual(&xwl_window->window->winSize, &present_window->winSize))
  433         return FALSE;
  434 
  435     return TRUE;
  436 }
  437 
  438 static Bool
  439 xwl_present_flip(WindowPtr present_window,
  440                  RRCrtcPtr crtc,
  441                  uint64_t event_id,
  442                  uint64_t target_msc,
  443                  PixmapPtr pixmap,
  444                  Bool sync_flip,
  445                  RegionPtr damage)
  446 {
  447     struct xwl_window           *xwl_window = xwl_window_from_window(present_window);
  448     struct xwl_present_window   *xwl_present_window = xwl_present_window_priv(present_window);
  449     BoxPtr                      damage_box;
  450     Bool                        buffer_created;
  451     struct wl_buffer            *buffer;
  452     struct xwl_present_event    *event;
  453 
  454     if (!xwl_window)
  455         return FALSE;
  456 
  457     damage_box = RegionExtents(damage);
  458 
  459     event = malloc(sizeof *event);
  460     if (!event)
  461         return FALSE;
  462 
  463     buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap, &buffer_created);
  464 
  465     event->event_id = event_id;
  466     event->xwl_present_window = xwl_present_window;
  467     event->buffer = buffer;
  468     event->target_msc = target_msc;
  469     event->pending = TRUE;
  470     event->abort = FALSE;
  471     event->buffer_released = FALSE;
  472 
  473     if (sync_flip) {
  474         xorg_list_init(&event->list);
  475         xwl_present_window->sync_flip = event;
  476     } else {
  477         xorg_list_add(&event->list, &xwl_present_window->release_queue);
  478     }
  479 
  480     if (buffer_created)
  481         wl_buffer_add_listener(buffer, &xwl_present_release_listener, NULL);
  482     wl_buffer_set_user_data(buffer, event);
  483 
  484     /* We can flip directly to the main surface (full screen window without clips) */
  485     wl_surface_attach(xwl_window->surface, buffer, 0, 0);
  486 
  487     if (!xwl_window->frame_callback)
  488         xwl_window_create_frame_callback(xwl_window);
  489 
  490     if (xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
  491         xorg_list_add(&xwl_present_window->frame_callback_list,
  492                       &xwl_window->frame_callback_list);
  493     }
  494 
  495     /* Realign timer */
  496     xwl_present_reset_timer(xwl_present_window);
  497 
  498     wl_surface_damage(xwl_window->surface, 0, 0,
  499                       damage_box->x2 - damage_box->x1,
  500                       damage_box->y2 - damage_box->y1);
  501 
  502     wl_surface_commit(xwl_window->surface);
  503 
  504     if (!sync_flip) {
  505         xwl_present_window->sync_callback =
  506             wl_display_sync(xwl_window->xwl_screen->display);
  507         wl_callback_add_listener(xwl_present_window->sync_callback,
  508                                  &xwl_present_sync_listener,
  509                                  event);
  510     }
  511 
  512     wl_display_flush(xwl_window->xwl_screen->display);
  513     xwl_window->present_flipped = TRUE;
  514     return TRUE;
  515 }
  516 
  517 static void
  518 xwl_present_flips_stop(WindowPtr window)
  519 {
  520     struct xwl_present_window   *xwl_present_window = xwl_present_window_priv(window);
  521 
  522     /* Change back to the fast refresh rate */
  523     xwl_present_reset_timer(xwl_present_window);
  524 }
  525 
  526 void
  527 xwl_present_unrealize_window(struct xwl_present_window *xwl_present_window)
  528 {
  529     /* The pending frame callback may never be called, so drop it and shorten
  530      * the frame timer interval.
  531      */
  532     xorg_list_del(&xwl_present_window->frame_callback_list);
  533     xwl_present_reset_timer(xwl_present_window);
  534 }
  535 
  536 static present_wnmd_info_rec xwl_present_info = {
  537     .version = PRESENT_SCREEN_INFO_VERSION,
  538     .get_crtc = xwl_present_get_crtc,
  539 
  540     .get_ust_msc = xwl_present_get_ust_msc,
  541     .queue_vblank = xwl_present_queue_vblank,
  542     .abort_vblank = xwl_present_abort_vblank,
  543 
  544     .flush = xwl_present_flush,
  545 
  546     .capabilities = PresentCapabilityAsync,
  547     .check_flip2 = xwl_present_check_flip2,
  548     .flip = xwl_present_flip,
  549     .flips_stop = xwl_present_flips_stop
  550 };
  551 
  552 Bool
  553 xwl_present_init(ScreenPtr screen)
  554 {
  555     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
  556 
  557     /*
  558      * doesn't work with the EGLStream backend.
  559      */
  560     if (xwl_screen->egl_backend == &xwl_screen->eglstream_backend)
  561         return FALSE;
  562 
  563     if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0))
  564         return FALSE;
  565 
  566     return present_wnmd_screen_init(screen, &xwl_present_info);
  567 }