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#ifdef USE_GLAMOR 258 struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); 259#endif 260 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 261 RADEONInfoPtr info = RADEONPTR(scrn); 262 PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); 263 int num_crtcs_on; 264 int i; 265 266 if (!scrn->vtSema) 267 return FALSE; 268 269 if (!info->allowPageFlip) 270 return FALSE; 271 272 if (info->sprites_visible > 0) 273 return FALSE; 274 275 if (info->drmmode.dri2_flipping) 276 return FALSE; 277 278#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1, 20, 99, 1, 0) 279 if (pixmap->devKind != screen_pixmap->devKind) 280 return FALSE; 281#endif 282 283#ifdef USE_GLAMOR 284 if (priv && priv->fb_failed) 285 return FALSE; 286#endif 287 288 if (!radeon_pixmap_get_fb(pixmap)) { 289#ifdef USE_GLAMOR 290 if (!priv) 291 priv = radeon_get_pixmap_private(pixmap); 292 293 if (priv && !priv->fb_failed) { 294 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 295 "Cannot get FB for Present flip (may be " 296 "normal if using PRIME render offloading)\n"); 297 priv->fb_failed = TRUE; 298 } 299#endif 300 301 return FALSE; 302 } 303 304 /* The kernel driver doesn't handle flipping between BOs with different 305 * tiling parameters correctly yet 306 */ 307 if (radeon_present_get_pixmap_tiling_flags(info, pixmap) != 308 radeon_present_get_pixmap_tiling_flags(info, screen_pixmap)) 309 return FALSE; 310 311 for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { 312 if (drmmode_crtc_can_flip(config->crtc[i])) 313 num_crtcs_on++; 314 else if (config->crtc[i] == crtc->devPrivate) 315 return FALSE; 316 } 317 318 if (num_crtcs_on == 0) 319 return FALSE; 320 321 return TRUE; 322} 323 324/* 325 * Once the flip has been completed on all CRTCs, notify the 326 * extension code telling it when that happened 327 */ 328static void 329radeon_present_flip_event(xf86CrtcPtr crtc, uint32_t msc, uint64_t ust, void *pageflip_data) 330{ 331 RADEONInfoPtr info = RADEONPTR(crtc->scrn); 332 struct radeon_present_vblank_event *event = pageflip_data; 333 334 if (event->unflip) 335 info->drmmode.present_flipping = FALSE; 336 337 present_event_notify(event->event_id, ust, msc); 338 free(event); 339} 340 341/* 342 * The flip has been aborted, free the structure 343 */ 344static void 345radeon_present_flip_abort(xf86CrtcPtr crtc, void *pageflip_data) 346{ 347 struct radeon_present_vblank_event *event = pageflip_data; 348 349 free(event); 350} 351 352/* 353 * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true, 354 * then wait for vblank. Otherwise, flip immediately 355 */ 356static Bool 357radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, 358 PixmapPtr pixmap, Bool sync_flip) 359{ 360 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 361 ScreenPtr screen = crtc->pScreen; 362 ScrnInfoPtr scrn = xf86_crtc->scrn; 363 RADEONInfoPtr info = RADEONPTR(scrn); 364 struct radeon_present_vblank_event *event; 365 Bool ret = FALSE; 366 367 if (!radeon_present_check_flip(crtc, screen->root, pixmap, sync_flip)) 368 return ret; 369 370 event = calloc(1, sizeof(struct radeon_present_vblank_event)); 371 if (!event) 372 return ret; 373 374 event->event_id = event_id; 375 376 radeon_cs_flush_indirect(scrn); 377 378 ret = radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, pixmap, 379 event_id, event, crtc->devPrivate, 380 radeon_present_flip_event, 381 radeon_present_flip_abort, 382 sync_flip ? FLIP_VSYNC : FLIP_ASYNC, 383 target_msc); 384 if (!ret) 385 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n"); 386 else 387 info->drmmode.present_flipping = TRUE; 388 389 return ret; 390} 391 392/* 393 * Queue a flip back to the normal frame buffer 394 */ 395static void 396radeon_present_unflip(ScreenPtr screen, uint64_t event_id) 397{ 398 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 399 RADEONInfoPtr info = RADEONPTR(scrn); 400 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 401 struct radeon_present_vblank_event *event; 402 PixmapPtr pixmap = screen->GetScreenPixmap(screen); 403 enum drmmode_flip_sync flip_sync = 404 (radeon_present_screen_info.capabilities & PresentCapabilityAsync) ? 405 FLIP_ASYNC : FLIP_VSYNC; 406 int i; 407 408 if (!radeon_present_check_unflip(scrn)) 409 goto modeset; 410 411 event = calloc(1, sizeof(struct radeon_present_vblank_event)); 412 if (!event) { 413 ErrorF("%s: calloc failed, display might freeze\n", __func__); 414 goto modeset; 415 } 416 417 event->event_id = event_id; 418 event->unflip = TRUE; 419 420 if (radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, pixmap, 421 event_id, event, NULL, radeon_present_flip_event, 422 radeon_present_flip_abort, flip_sync, 0)) 423 return; 424 425modeset: 426 radeon_finish(scrn, info->front_buffer); 427 for (i = 0; i < config->num_crtc; i++) { 428 xf86CrtcPtr crtc = config->crtc[i]; 429 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 430 431 if (!crtc->enabled || drmmode_crtc->tear_free) 432 continue; 433 434 if (drmmode_crtc->dpms_mode == DPMSModeOn) 435 crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 436 crtc->x, crtc->y); 437 else 438 drmmode_crtc->need_modeset = TRUE; 439 } 440 441 present_event_notify(event_id, 0, 0); 442 443 info->drmmode.present_flipping = FALSE; 444} 445 446static present_screen_info_rec radeon_present_screen_info = { 447 .version = 0, 448 449 .get_crtc = radeon_present_get_crtc, 450 .get_ust_msc = radeon_present_get_ust_msc, 451 .queue_vblank = radeon_present_queue_vblank, 452 .abort_vblank = radeon_present_abort_vblank, 453 .flush = radeon_present_flush, 454 455 .capabilities = PresentCapabilityNone, 456 .check_flip = radeon_present_check_flip, 457 .flip = radeon_present_flip, 458 .unflip = radeon_present_unflip, 459}; 460 461static Bool 462radeon_present_has_async_flip(ScreenPtr screen) 463{ 464#ifdef DRM_CAP_ASYNC_PAGE_FLIP 465 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 466 RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 467 int ret; 468 uint64_t value; 469 470 ret = drmGetCap(pRADEONEnt->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); 471 if (ret == 0) 472 return value == 1; 473#endif 474 return FALSE; 475} 476 477Bool 478radeon_present_screen_init(ScreenPtr screen) 479{ 480 if (radeon_present_has_async_flip(screen)) 481 radeon_present_screen_info.capabilities |= PresentCapabilityAsync; 482 483 if (!present_screen_init(screen, &radeon_present_screen_info)) { 484 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_WARNING, 485 "Present extension disabled because present_screen_init failed\n"); 486 return FALSE; 487 } 488 489 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 490 "Present extension enabled\n"); 491 492 return TRUE; 493} 494 495#else /* !HAVE_PRESENT_H */ 496 497Bool 498radeon_present_screen_init(ScreenPtr screen) 499{ 500 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 501 "Present extension disabled because present.h not available at " 502 "build time\n"); 503 504 return FALSE; 505} 506 507#endif 508