radeon_present.c revision 0d2a5547
1/* 2 * Copyright © 2014 Intel Corporation 3 * Copyright © 2015 Advanced Micro Devices, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that copyright 8 * notice and this permission notice appear in supporting documentation, and 9 * that the name of the copyright holders not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. The copyright holders make no representations 12 * about the suitability of this software for any purpose. It is provided "as 13 * is" without express or implied warranty. 14 * 15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 21 * OF THIS SOFTWARE. 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include "config.h" 26#endif 27 28#include "radeon.h" 29 30#ifdef HAVE_PRESENT_H 31 32#include <stdio.h> 33#include <string.h> 34#include <assert.h> 35#include <sys/types.h> 36#include <sys/stat.h> 37#include <sys/ioctl.h> 38#include <unistd.h> 39#include <fcntl.h> 40#include <poll.h> 41#include <sys/time.h> 42#include <time.h> 43#include <errno.h> 44 45#include "radeon_bo_helper.h" 46#include "radeon_glamor.h" 47#include "radeon_video.h" 48 49#include "present.h" 50 51static present_screen_info_rec radeon_present_screen_info; 52 53struct radeon_present_vblank_event { 54 uint64_t event_id; 55 Bool unflip; 56}; 57 58static RRCrtcPtr 59radeon_present_get_crtc(WindowPtr window) 60{ 61 ScreenPtr screen = window->drawable.pScreen; 62 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 63 xf86CrtcPtr crtc; 64 RRCrtcPtr randr_crtc = NULL; 65 66 crtc = radeon_pick_best_crtc(pScrn, FALSE, 67 window->drawable.x, 68 window->drawable.x + window->drawable.width, 69 window->drawable.y, 70 window->drawable.y + window->drawable.height); 71 72 if (crtc) 73 randr_crtc = crtc->randr_crtc; 74 75 return randr_crtc; 76} 77 78static int 79radeon_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc) 80{ 81 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 82 drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; 83 84 if (drmmode_crtc->dpms_mode != DPMSModeOn) 85 return BadAlloc; 86 87 return drmmode_crtc_get_ust_msc(xf86_crtc, ust, msc); 88} 89 90/* 91 * Flush the DRM event queue when full; this 92 * makes space for new requests 93 */ 94static Bool 95radeon_present_flush_drm_events(ScreenPtr screen) 96{ 97 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 98 RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 99 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 100 drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[0]->driver_private; 101 drmmode_ptr drmmode = drmmode_crtc->drmmode; 102 struct pollfd p = { .fd = pRADEONEnt->fd, .events = POLLIN }; 103 int r; 104 105 do { 106 r = poll(&p, 1, 0); 107 } while (r == -1 && (errno == EINTR || errno == EAGAIN)); 108 109 if (r <= 0) 110 return 0; 111 112 return radeon_drm_handle_event(pRADEONEnt->fd, &drmmode->event_context) >= 0; 113} 114 115/* 116 * Called when the queued vblank event has occurred 117 */ 118static void 119radeon_present_vblank_handler(xf86CrtcPtr crtc, unsigned int msc, 120 uint64_t usec, void *data) 121{ 122 struct radeon_present_vblank_event *event = data; 123 124 present_event_notify(event->event_id, usec, msc); 125 free(event); 126} 127 128/* 129 * Called when the queued vblank is aborted 130 */ 131static void 132radeon_present_vblank_abort(xf86CrtcPtr crtc, void *data) 133{ 134 struct radeon_present_vblank_event *event = data; 135 136 free(event); 137} 138 139/* 140 * Queue an event to report back to the Present extension when the specified 141 * MSC has past 142 */ 143static int 144radeon_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) 145{ 146 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 147 ScreenPtr screen = crtc->pScreen; 148 struct radeon_present_vblank_event *event; 149 uintptr_t drm_queue_seq; 150 151 event = calloc(sizeof(struct radeon_present_vblank_event), 1); 152 if (!event) 153 return BadAlloc; 154 event->event_id = event_id; 155 156 drm_queue_seq = radeon_drm_queue_alloc(xf86_crtc, 157 RADEON_DRM_QUEUE_CLIENT_DEFAULT, 158 event_id, event, 159 radeon_present_vblank_handler, 160 radeon_present_vblank_abort, 161 FALSE); 162 if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 163 free(event); 164 return BadAlloc; 165 } 166 167 for (;;) { 168 if (drmmode_wait_vblank(xf86_crtc, 169 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT, msc, 170 drm_queue_seq, NULL, NULL)) 171 break; 172 if (errno != EBUSY || !radeon_present_flush_drm_events(screen)) { 173 radeon_drm_abort_entry(drm_queue_seq); 174 return BadAlloc; 175 } 176 } 177 178 return Success; 179} 180 181/* 182 * Remove a pending vblank event from the DRM queue so that it is not reported 183 * to the extension 184 */ 185static void 186radeon_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) 187{ 188 radeon_drm_abort_id(event_id); 189} 190 191/* 192 * Flush our batch buffer when requested by the Present extension. 193 */ 194static void 195radeon_present_flush(WindowPtr window) 196{ 197 radeon_cs_flush_indirect(xf86ScreenToScrn(window->drawable.pScreen)); 198} 199 200static uint32_t 201radeon_present_get_pixmap_tiling_flags(RADEONInfoPtr info, PixmapPtr pixmap) 202{ 203 uint32_t tiling_flags = radeon_get_pixmap_tiling_flags(pixmap); 204 205 /* Micro tiling is always enabled with macro tiling on >= R600, so we 206 * can ignore the micro tiling bit in that case 207 */ 208 if ((tiling_flags & RADEON_TILING_MACRO) && 209 info->ChipFamily >= CHIP_FAMILY_R600) 210 tiling_flags &= ~RADEON_TILING_MICRO; 211 212 return tiling_flags; 213} 214 215/* 216 * Test to see if unflipping is possible 217 * 218 * These tests have to pass for flips as well 219 */ 220static Bool 221radeon_present_check_unflip(ScrnInfoPtr scrn) 222{ 223 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 224 int num_crtcs_on; 225 int i; 226 227 if (!scrn->vtSema) 228 return FALSE; 229 230 for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { 231 xf86CrtcPtr crtc = config->crtc[i]; 232 233 if (drmmode_crtc_can_flip(crtc)) { 234 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 235 236 if (drmmode_crtc->flip_pending) 237 return FALSE; 238 239 if (!drmmode_crtc->tear_free) 240 num_crtcs_on++; 241 } 242 } 243 244 return num_crtcs_on > 0; 245} 246 247/* 248 * Test to see if page flipping is possible on the target crtc 249 */ 250static Bool 251radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, 252 Bool sync_flip) 253{ 254 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 255 ScreenPtr screen = window->drawable.pScreen; 256 ScrnInfoPtr scrn = xf86_crtc->scrn; 257 struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); 258 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 259 RADEONInfoPtr info = RADEONPTR(scrn); 260 PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); 261 int num_crtcs_on; 262 int i; 263 264 if (!scrn->vtSema) 265 return FALSE; 266 267 if (!info->allowPageFlip) 268 return FALSE; 269 270 if (info->sprites_visible > 0) 271 return FALSE; 272 273 if (info->drmmode.dri2_flipping) 274 return FALSE; 275 276#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1, 20, 99, 1, 0) 277 if (pixmap->devKind != screen_pixmap->devKind) 278 return FALSE; 279#endif 280 281 if (priv && priv->fb_failed) 282 return FALSE; 283 284 if (!radeon_pixmap_get_fb(pixmap)) { 285 if (!priv) 286 priv = radeon_get_pixmap_private(pixmap); 287 288 if (priv && !priv->fb_failed) { 289 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 290 "Cannot get FB for Present flip (may be " 291 "normal if using PRIME render offloading)\n"); 292 priv->fb_failed = TRUE; 293 } 294 295 return FALSE; 296 } 297 298 /* The kernel driver doesn't handle flipping between BOs with different 299 * tiling parameters correctly yet 300 */ 301 if (radeon_present_get_pixmap_tiling_flags(info, pixmap) != 302 radeon_present_get_pixmap_tiling_flags(info, screen_pixmap)) 303 return FALSE; 304 305 for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { 306 if (drmmode_crtc_can_flip(config->crtc[i])) 307 num_crtcs_on++; 308 else if (config->crtc[i] == crtc->devPrivate) 309 return FALSE; 310 } 311 312 if (num_crtcs_on == 0) 313 return FALSE; 314 315 return TRUE; 316} 317 318/* 319 * Once the flip has been completed on all CRTCs, notify the 320 * extension code telling it when that happened 321 */ 322static void 323radeon_present_flip_event(xf86CrtcPtr crtc, uint32_t msc, uint64_t ust, void *pageflip_data) 324{ 325 RADEONInfoPtr info = RADEONPTR(crtc->scrn); 326 struct radeon_present_vblank_event *event = pageflip_data; 327 328 if (event->unflip) 329 info->drmmode.present_flipping = FALSE; 330 331 present_event_notify(event->event_id, ust, msc); 332 free(event); 333} 334 335/* 336 * The flip has been aborted, free the structure 337 */ 338static void 339radeon_present_flip_abort(xf86CrtcPtr crtc, void *pageflip_data) 340{ 341 struct radeon_present_vblank_event *event = pageflip_data; 342 343 free(event); 344} 345 346/* 347 * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true, 348 * then wait for vblank. Otherwise, flip immediately 349 */ 350static Bool 351radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, 352 PixmapPtr pixmap, Bool sync_flip) 353{ 354 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 355 ScreenPtr screen = crtc->pScreen; 356 ScrnInfoPtr scrn = xf86_crtc->scrn; 357 RADEONInfoPtr info = RADEONPTR(scrn); 358 struct radeon_present_vblank_event *event; 359 Bool ret = FALSE; 360 361 if (!radeon_present_check_flip(crtc, screen->root, pixmap, sync_flip)) 362 return ret; 363 364 event = calloc(1, sizeof(struct radeon_present_vblank_event)); 365 if (!event) 366 return ret; 367 368 event->event_id = event_id; 369 370 radeon_cs_flush_indirect(scrn); 371 372 ret = radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, pixmap, 373 event_id, event, crtc->devPrivate, 374 radeon_present_flip_event, 375 radeon_present_flip_abort, 376 sync_flip ? FLIP_VSYNC : FLIP_ASYNC, 377 target_msc); 378 if (!ret) 379 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n"); 380 else 381 info->drmmode.present_flipping = TRUE; 382 383 return ret; 384} 385 386/* 387 * Queue a flip back to the normal frame buffer 388 */ 389static void 390radeon_present_unflip(ScreenPtr screen, uint64_t event_id) 391{ 392 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 393 RADEONInfoPtr info = RADEONPTR(scrn); 394 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 395 struct radeon_present_vblank_event *event; 396 PixmapPtr pixmap = screen->GetScreenPixmap(screen); 397 enum drmmode_flip_sync flip_sync = 398 (radeon_present_screen_info.capabilities & PresentCapabilityAsync) ? 399 FLIP_ASYNC : FLIP_VSYNC; 400 int i; 401 402 if (!radeon_present_check_unflip(scrn)) 403 goto modeset; 404 405 event = calloc(1, sizeof(struct radeon_present_vblank_event)); 406 if (!event) { 407 ErrorF("%s: calloc failed, display might freeze\n", __func__); 408 goto modeset; 409 } 410 411 event->event_id = event_id; 412 event->unflip = TRUE; 413 414 if (radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, pixmap, 415 event_id, event, NULL, radeon_present_flip_event, 416 radeon_present_flip_abort, flip_sync, 0)) 417 return; 418 419modeset: 420 radeon_finish(scrn, info->front_buffer); 421 for (i = 0; i < config->num_crtc; i++) { 422 xf86CrtcPtr crtc = config->crtc[i]; 423 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 424 425 if (!crtc->enabled || drmmode_crtc->tear_free) 426 continue; 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 437 info->drmmode.present_flipping = FALSE; 438} 439 440static present_screen_info_rec radeon_present_screen_info = { 441 .version = 0, 442 443 .get_crtc = radeon_present_get_crtc, 444 .get_ust_msc = radeon_present_get_ust_msc, 445 .queue_vblank = radeon_present_queue_vblank, 446 .abort_vblank = radeon_present_abort_vblank, 447 .flush = radeon_present_flush, 448 449 .capabilities = PresentCapabilityNone, 450 .check_flip = radeon_present_check_flip, 451 .flip = radeon_present_flip, 452 .unflip = radeon_present_unflip, 453}; 454 455static Bool 456radeon_present_has_async_flip(ScreenPtr screen) 457{ 458#ifdef DRM_CAP_ASYNC_PAGE_FLIP 459 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 460 RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 461 int ret; 462 uint64_t value; 463 464 ret = drmGetCap(pRADEONEnt->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); 465 if (ret == 0) 466 return value == 1; 467#endif 468 return FALSE; 469} 470 471Bool 472radeon_present_screen_init(ScreenPtr screen) 473{ 474 if (radeon_present_has_async_flip(screen)) 475 radeon_present_screen_info.capabilities |= PresentCapabilityAsync; 476 477 if (!present_screen_init(screen, &radeon_present_screen_info)) { 478 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_WARNING, 479 "Present extension disabled because present_screen_init failed\n"); 480 return FALSE; 481 } 482 483 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 484 "Present extension enabled\n"); 485 486 return TRUE; 487} 488 489#else /* !HAVE_PRESENT_H */ 490 491Bool 492radeon_present_screen_init(ScreenPtr screen) 493{ 494 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 495 "Present extension disabled because present.h not available at " 496 "build time\n"); 497 498 return FALSE; 499} 500 501#endif 502