xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

present.c (13159B)


      1 /*
      2  * Copyright © 2014 Intel Corporation
      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_DIX_CONFIG_H
     24 #include "dix-config.h"
     25 #endif
     26 
     27 #include <assert.h>
     28 #include <errno.h>
     29 #include <fcntl.h>
     30 #include <unistd.h>
     31 #include <stdio.h>
     32 #include <stdint.h>
     33 #include <string.h>
     34 #include <sys/ioctl.h>
     35 #include <sys/time.h>
     36 #include <sys/types.h>
     37 #include <time.h>
     38 
     39 #include <xf86.h>
     40 #include <xf86Crtc.h>
     41 #include <xf86drm.h>
     42 #include <xf86str.h>
     43 #include <present.h>
     44 
     45 #include "driver.h"
     46 #include "drmmode_display.h"
     47 
     48 #if 0
     49 #define DebugPresent(x) ErrorF x
     50 #else
     51 #define DebugPresent(x)
     52 #endif
     53 
     54 struct ms_present_vblank_event {
     55     uint64_t        event_id;
     56     Bool            unflip;
     57 };
     58 
     59 static RRCrtcPtr
     60 ms_present_get_crtc(WindowPtr window)
     61 {
     62     return ms_randr_crtc_covering_drawable(&window->drawable);
     63 }
     64 
     65 static int
     66 ms_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc)
     67 {
     68     xf86CrtcPtr xf86_crtc = crtc->devPrivate;
     69 
     70     return ms_get_crtc_ust_msc(xf86_crtc, ust, msc);
     71 }
     72 
     73 /*
     74  * Changes the variable refresh state for every CRTC on the screen.
     75  */
     76 void
     77 ms_present_set_screen_vrr(ScrnInfoPtr scrn, Bool vrr_enabled)
     78 {
     79     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
     80     xf86CrtcPtr crtc;
     81     int i;
     82 
     83     for (i = 0; i < config->num_crtc; i++) {
     84         crtc = config->crtc[i];
     85         drmmode_crtc_set_vrr(crtc, vrr_enabled);
     86     }
     87 }
     88 
     89 /*
     90  * Called when the queued vblank event has occurred
     91  */
     92 static void
     93 ms_present_vblank_handler(uint64_t msc, uint64_t usec, void *data)
     94 {
     95     struct ms_present_vblank_event *event = data;
     96 
     97     DebugPresent(("\t\tmh %lld msc %llu\n",
     98                  (long long) event->event_id, (long long) msc));
     99 
    100     present_event_notify(event->event_id, usec, msc);
    101     free(event);
    102 }
    103 
    104 /*
    105  * Called when the queued vblank is aborted
    106  */
    107 static void
    108 ms_present_vblank_abort(void *data)
    109 {
    110     struct ms_present_vblank_event *event = data;
    111 
    112     DebugPresent(("\t\tma %lld\n", (long long) event->event_id));
    113 
    114     free(event);
    115 }
    116 
    117 /*
    118  * Queue an event to report back to the Present extension when the specified
    119  * MSC has past
    120  */
    121 static int
    122 ms_present_queue_vblank(RRCrtcPtr crtc,
    123                         uint64_t event_id,
    124                         uint64_t msc)
    125 {
    126     xf86CrtcPtr xf86_crtc = crtc->devPrivate;
    127     struct ms_present_vblank_event *event;
    128     uint32_t seq;
    129 
    130     event = calloc(sizeof(struct ms_present_vblank_event), 1);
    131     if (!event)
    132         return BadAlloc;
    133     event->event_id = event_id;
    134     seq = ms_drm_queue_alloc(xf86_crtc, event,
    135                              ms_present_vblank_handler,
    136                              ms_present_vblank_abort);
    137     if (!seq) {
    138         free(event);
    139         return BadAlloc;
    140     }
    141 
    142     if (!ms_queue_vblank(xf86_crtc, MS_QUEUE_ABSOLUTE, msc, NULL, seq))
    143         return BadAlloc;
    144 
    145     DebugPresent(("\t\tmq %lld seq %u msc %llu\n",
    146                  (long long) event_id, seq, (long long) msc));
    147     return Success;
    148 }
    149 
    150 static Bool
    151 ms_present_event_match(void *data, void *match_data)
    152 {
    153     struct ms_present_vblank_event *event = data;
    154     uint64_t *match = match_data;
    155 
    156     return *match == event->event_id;
    157 }
    158 
    159 /*
    160  * Remove a pending vblank event from the DRM queue so that it is not reported
    161  * to the extension
    162  */
    163 static void
    164 ms_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
    165 {
    166     ScreenPtr screen = crtc->pScreen;
    167     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    168 
    169     ms_drm_abort(scrn, ms_present_event_match, &event_id);
    170 }
    171 
    172 /*
    173  * Flush our batch buffer when requested by the Present extension.
    174  */
    175 static void
    176 ms_present_flush(WindowPtr window)
    177 {
    178 #ifdef GLAMOR_HAS_GBM
    179     ScreenPtr screen = window->drawable.pScreen;
    180     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    181     modesettingPtr ms = modesettingPTR(scrn);
    182 
    183     if (ms->drmmode.glamor)
    184         ms->glamor.block_handler(screen);
    185 #endif
    186 }
    187 
    188 #ifdef GLAMOR_HAS_GBM
    189 
    190 /**
    191  * Callback for the DRM event queue when a flip has completed on all pipes
    192  *
    193  * Notify the extension code
    194  */
    195 static void
    196 ms_present_flip_handler(modesettingPtr ms, uint64_t msc,
    197                         uint64_t ust, void *data)
    198 {
    199     struct ms_present_vblank_event *event = data;
    200 
    201     DebugPresent(("\t\tms:fc %lld msc %llu ust %llu\n",
    202                   (long long) event->event_id,
    203                   (long long) msc, (long long) ust));
    204 
    205     if (event->unflip)
    206         ms->drmmode.present_flipping = FALSE;
    207 
    208     ms_present_vblank_handler(msc, ust, event);
    209 }
    210 
    211 /*
    212  * Callback for the DRM queue abort code.  A flip has been aborted.
    213  */
    214 static void
    215 ms_present_flip_abort(modesettingPtr ms, void *data)
    216 {
    217     struct ms_present_vblank_event *event = data;
    218 
    219     DebugPresent(("\t\tms:fa %lld\n", (long long) event->event_id));
    220 
    221     free(event);
    222 }
    223 
    224 /*
    225  * Test to see if page flipping is possible on the target crtc
    226  *
    227  * We ignore sw-cursors when *disabling* flipping, we may very well be
    228  * returning to scanning out the normal framebuffer *because* we just
    229  * switched to sw-cursor mode and check_flip just failed because of that.
    230  */
    231 static Bool
    232 ms_present_check_unflip(RRCrtcPtr crtc,
    233                         WindowPtr window,
    234                         PixmapPtr pixmap,
    235                         Bool sync_flip,
    236                         PresentFlipReason *reason)
    237 {
    238     ScreenPtr screen = window->drawable.pScreen;
    239     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    240     modesettingPtr ms = modesettingPTR(scrn);
    241     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
    242     int num_crtcs_on = 0;
    243     int i;
    244     struct gbm_bo *gbm;
    245 
    246     if (!ms->drmmode.pageflip)
    247         return FALSE;
    248 
    249     if (ms->drmmode.dri2_flipping)
    250         return FALSE;
    251 
    252     if (!scrn->vtSema)
    253         return FALSE;
    254 
    255     for (i = 0; i < config->num_crtc; i++) {
    256         drmmode_crtc_private_ptr drmmode_crtc = config->crtc[i]->driver_private;
    257 
    258         /* Don't do pageflipping if CRTCs are rotated. */
    259         if (drmmode_crtc->rotate_bo.gbm)
    260             return FALSE;
    261 
    262         if (xf86_crtc_on(config->crtc[i]))
    263             num_crtcs_on++;
    264     }
    265 
    266     /* We can't do pageflipping if all the CRTCs are off. */
    267     if (num_crtcs_on == 0)
    268         return FALSE;
    269 
    270     /*
    271      * Check stride, can't change that reliably on flip on some drivers, unless
    272      * the kms driver is atomic_modeset_capable.
    273      */
    274     if (!ms->atomic_modeset_capable &&
    275         pixmap->devKind != drmmode_bo_get_pitch(&ms->drmmode.front_bo))
    276         return FALSE;
    277 
    278     if (!ms->drmmode.glamor)
    279         return FALSE;
    280 
    281 #ifdef GBM_BO_WITH_MODIFIERS
    282     /* Check if buffer format/modifier is supported by all active CRTCs */
    283     gbm = ms->glamor.gbm_bo_from_pixmap(screen, pixmap);
    284     if (gbm) {
    285         uint32_t format;
    286         uint64_t modifier;
    287 
    288         format = gbm_bo_get_format(gbm);
    289         modifier = gbm_bo_get_modifier(gbm);
    290         gbm_bo_destroy(gbm);
    291 
    292         if (!drmmode_is_format_supported(scrn, format, modifier)) {
    293             if (reason)
    294                 *reason = PRESENT_FLIP_REASON_BUFFER_FORMAT;
    295             return FALSE;
    296         }
    297     }
    298 #endif
    299 
    300     /* Make sure there's a bo we can get to */
    301     /* XXX: actually do this.  also...is it sufficient?
    302      * if (!glamor_get_pixmap_private(pixmap))
    303      *     return FALSE;
    304      */
    305 
    306     return TRUE;
    307 }
    308 
    309 static Bool
    310 ms_present_check_flip(RRCrtcPtr crtc,
    311                       WindowPtr window,
    312                       PixmapPtr pixmap,
    313                       Bool sync_flip,
    314                       PresentFlipReason *reason)
    315 {
    316     ScreenPtr screen = window->drawable.pScreen;
    317     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    318     modesettingPtr ms = modesettingPTR(scrn);
    319 
    320     if (ms->drmmode.sprites_visible > 0)
    321         return FALSE;
    322 
    323     if(!ms_present_check_unflip(crtc, window, pixmap, sync_flip, reason))
    324         return FALSE;
    325 
    326     ms->flip_window = window;
    327 
    328     return TRUE;
    329 }
    330 
    331 /*
    332  * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true,
    333  * then wait for vblank. Otherwise, flip immediately
    334  */
    335 static Bool
    336 ms_present_flip(RRCrtcPtr crtc,
    337                 uint64_t event_id,
    338                 uint64_t target_msc,
    339                 PixmapPtr pixmap,
    340                 Bool sync_flip)
    341 {
    342     ScreenPtr screen = crtc->pScreen;
    343     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    344     modesettingPtr ms = modesettingPTR(scrn);
    345     xf86CrtcPtr xf86_crtc = crtc->devPrivate;
    346     drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
    347     Bool ret;
    348     struct ms_present_vblank_event *event;
    349 
    350     if (!ms_present_check_flip(crtc, ms->flip_window, pixmap, sync_flip, NULL))
    351         return FALSE;
    352 
    353     event = calloc(1, sizeof(struct ms_present_vblank_event));
    354     if (!event)
    355         return FALSE;
    356 
    357     DebugPresent(("\t\tms:pf %lld msc %llu\n",
    358                   (long long) event_id, (long long) target_msc));
    359 
    360     event->event_id = event_id;
    361     event->unflip = FALSE;
    362 
    363     /* A window can only flip if it covers the entire X screen.
    364      * Only one window can flip at a time.
    365      *
    366      * If the window also has the variable refresh property then
    367      * variable refresh supported can be enabled on every CRTC.
    368      */
    369     if (ms->vrr_support && ms->is_connector_vrr_capable &&
    370           ms_window_has_variable_refresh(ms, ms->flip_window)) {
    371         ms_present_set_screen_vrr(scrn, TRUE);
    372     }
    373 
    374     ret = ms_do_pageflip(screen, pixmap, event, drmmode_crtc->vblank_pipe, !sync_flip,
    375                          ms_present_flip_handler, ms_present_flip_abort,
    376                          "Present-flip");
    377     if (ret)
    378         ms->drmmode.present_flipping = TRUE;
    379 
    380     return ret;
    381 }
    382 
    383 /*
    384  * Queue a flip back to the normal frame buffer
    385  */
    386 static void
    387 ms_present_unflip(ScreenPtr screen, uint64_t event_id)
    388 {
    389     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    390     modesettingPtr ms = modesettingPTR(scrn);
    391     PixmapPtr pixmap = screen->GetScreenPixmap(screen);
    392     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
    393     int i;
    394     struct ms_present_vblank_event *event;
    395 
    396     ms_present_set_screen_vrr(scrn, FALSE);
    397 
    398     event = calloc(1, sizeof(struct ms_present_vblank_event));
    399     if (!event)
    400         return;
    401 
    402     event->event_id = event_id;
    403     event->unflip = TRUE;
    404 
    405     if (ms_present_check_unflip(NULL, screen->root, pixmap, TRUE, NULL) &&
    406         ms_do_pageflip(screen, pixmap, event, -1, FALSE,
    407                        ms_present_flip_handler, ms_present_flip_abort,
    408                        "Present-unflip")) {
    409         return;
    410     }
    411 
    412     for (i = 0; i < config->num_crtc; i++) {
    413         xf86CrtcPtr crtc = config->crtc[i];
    414 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    415 
    416 	if (!crtc->enabled)
    417 	    continue;
    418 
    419 	/* info->drmmode.fb_id still points to the FB for the last flipped BO.
    420 	 * Clear it, drmmode_set_mode_major will re-create it
    421 	 */
    422 	if (drmmode_crtc->drmmode->fb_id) {
    423 		drmModeRmFB(drmmode_crtc->drmmode->fd,
    424 			    drmmode_crtc->drmmode->fb_id);
    425 		drmmode_crtc->drmmode->fb_id = 0;
    426 	}
    427 
    428 	if (drmmode_crtc->dpms_mode == DPMSModeOn)
    429 	    crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
    430 					crtc->x, crtc->y);
    431 	else
    432 	    drmmode_crtc->need_modeset = TRUE;
    433     }
    434 
    435     present_event_notify(event_id, 0, 0);
    436     ms->drmmode.present_flipping = FALSE;
    437 }
    438 #endif
    439 
    440 static present_screen_info_rec ms_present_screen_info = {
    441     .version = PRESENT_SCREEN_INFO_VERSION,
    442 
    443     .get_crtc = ms_present_get_crtc,
    444     .get_ust_msc = ms_present_get_ust_msc,
    445     .queue_vblank = ms_present_queue_vblank,
    446     .abort_vblank = ms_present_abort_vblank,
    447     .flush = ms_present_flush,
    448 
    449     .capabilities = PresentCapabilityNone,
    450 #ifdef GLAMOR_HAS_GBM
    451     .check_flip = NULL,
    452     .check_flip2 = ms_present_check_flip,
    453     .flip = ms_present_flip,
    454     .unflip = ms_present_unflip,
    455 #endif
    456 };
    457 
    458 Bool
    459 ms_present_screen_init(ScreenPtr screen)
    460 {
    461     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    462     modesettingPtr ms = modesettingPTR(scrn);
    463     uint64_t value;
    464     int ret;
    465 
    466     ret = drmGetCap(ms->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value);
    467     if (ret == 0 && value == 1) {
    468         ms_present_screen_info.capabilities |= PresentCapabilityAsync;
    469         ms->drmmode.can_async_flip = TRUE;
    470     }
    471 
    472     return present_screen_init(screen, &ms_present_screen_info);
    473 }