radeon_present.c revision 3ed65abb
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 uint32_t crtc_select(int crtc_id) 59{ 60 if (crtc_id > 1) 61 return crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT; 62 else if (crtc_id > 0) 63 return DRM_VBLANK_SECONDARY; 64 else 65 return 0; 66} 67 68static RRCrtcPtr 69radeon_present_get_crtc(WindowPtr window) 70{ 71 ScreenPtr screen = window->drawable.pScreen; 72 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 73 xf86CrtcPtr crtc; 74 RRCrtcPtr randr_crtc = NULL; 75 76 crtc = radeon_pick_best_crtc(pScrn, FALSE, 77 window->drawable.x, 78 window->drawable.x + window->drawable.width, 79 window->drawable.y, 80 window->drawable.y + window->drawable.height); 81 82 if (crtc) 83 randr_crtc = crtc->randr_crtc; 84 85 return randr_crtc; 86} 87 88static int 89radeon_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc) 90{ 91 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 92 drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; 93 94 if (drmmode_crtc->dpms_mode != DPMSModeOn) 95 return BadAlloc; 96 97 return drmmode_crtc_get_ust_msc(xf86_crtc, ust, msc); 98} 99 100/* 101 * Flush the DRM event queue when full; this 102 * makes space for new requests 103 */ 104static Bool 105radeon_present_flush_drm_events(ScreenPtr screen) 106{ 107 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 108 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 109 drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[0]->driver_private; 110 drmmode_ptr drmmode = drmmode_crtc->drmmode; 111 struct pollfd p = { .fd = drmmode->fd, .events = POLLIN }; 112 int r; 113 114 do { 115 r = poll(&p, 1, 0); 116 } while (r == -1 && (errno == EINTR || errno == EAGAIN)); 117 118 if (r <= 0) 119 return 0; 120 121 return drmHandleEvent(drmmode->fd, &drmmode->event_context) >= 0; 122} 123 124/* 125 * Called when the queued vblank event has occurred 126 */ 127static void 128radeon_present_vblank_handler(xf86CrtcPtr crtc, unsigned int msc, 129 uint64_t usec, void *data) 130{ 131 struct radeon_present_vblank_event *event = data; 132 133 present_event_notify(event->event_id, usec, msc); 134 free(event); 135} 136 137/* 138 * Called when the queued vblank is aborted 139 */ 140static void 141radeon_present_vblank_abort(xf86CrtcPtr crtc, void *data) 142{ 143 struct radeon_present_vblank_event *event = data; 144 145 free(event); 146} 147 148/* 149 * Queue an event to report back to the Present extension when the specified 150 * MSC has past 151 */ 152static int 153radeon_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) 154{ 155 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 156 ScreenPtr screen = crtc->pScreen; 157 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 158 RADEONInfoPtr info = RADEONPTR(scrn); 159 int crtc_id = drmmode_get_crtc_id(xf86_crtc); 160 struct radeon_present_vblank_event *event; 161 uintptr_t drm_queue_seq; 162 drmVBlank vbl; 163 int ret; 164 165 event = calloc(sizeof(struct radeon_present_vblank_event), 1); 166 if (!event) 167 return BadAlloc; 168 event->event_id = event_id; 169 drm_queue_seq = radeon_drm_queue_alloc(xf86_crtc, 170 RADEON_DRM_QUEUE_CLIENT_DEFAULT, 171 event_id, event, 172 radeon_present_vblank_handler, 173 radeon_present_vblank_abort); 174 if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 175 free(event); 176 return BadAlloc; 177 } 178 179 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | crtc_select(crtc_id); 180 vbl.request.sequence = msc; 181 vbl.request.signal = drm_queue_seq; 182 for (;;) { 183 ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 184 if (!ret) 185 break; 186 if (errno != EBUSY || !radeon_present_flush_drm_events(screen)) { 187 radeon_drm_abort_entry(drm_queue_seq); 188 return BadAlloc; 189 } 190 } 191 192 return Success; 193} 194 195/* 196 * Remove a pending vblank event from the DRM queue so that it is not reported 197 * to the extension 198 */ 199static void 200radeon_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) 201{ 202 radeon_drm_abort_id(event_id); 203} 204 205/* 206 * Flush our batch buffer when requested by the Present extension. 207 */ 208static void 209radeon_present_flush(WindowPtr window) 210{ 211 radeon_cs_flush_indirect(xf86ScreenToScrn(window->drawable.pScreen)); 212} 213 214static uint32_t 215radeon_present_get_pixmap_tiling_flags(RADEONInfoPtr info, PixmapPtr pixmap) 216{ 217 uint32_t tiling_flags = radeon_get_pixmap_tiling_flags(pixmap); 218 219 /* Micro tiling is always enabled with macro tiling on >= R600, so we 220 * can ignore the micro tiling bit in that case 221 */ 222 if ((tiling_flags & RADEON_TILING_MACRO) && 223 info->ChipFamily >= CHIP_FAMILY_R600) 224 tiling_flags &= ~RADEON_TILING_MICRO; 225 226 return tiling_flags; 227} 228 229/* 230 * Test to see if unflipping is possible 231 * 232 * These tests have to pass for flips as well 233 */ 234static Bool 235radeon_present_check_unflip(ScrnInfoPtr scrn) 236{ 237 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 238 int num_crtcs_on; 239 int i; 240 241 if (!scrn->vtSema) 242 return FALSE; 243 244 for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { 245 drmmode_crtc_private_ptr drmmode_crtc = config->crtc[i]->driver_private; 246 247 if (!config->crtc[i]->enabled) 248 continue; 249 250 if (!drmmode_crtc || drmmode_crtc->rotate.bo || 251 drmmode_crtc->scanout[0].bo) 252 return FALSE; 253 254 if (drmmode_crtc->pending_dpms_mode == DPMSModeOn) 255 num_crtcs_on++; 256 } 257 258 return num_crtcs_on > 0; 259} 260 261/* 262 * Test to see if page flipping is possible on the target crtc 263 */ 264static Bool 265radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, 266 Bool sync_flip) 267{ 268 ScreenPtr screen = window->drawable.pScreen; 269 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 270 RADEONInfoPtr info = RADEONPTR(scrn); 271 PixmapPtr screen_pixmap; 272 273 if (!info->allowPageFlip) 274 return FALSE; 275 276 if (info->hwcursor_disabled) 277 return FALSE; 278 279 if (info->drmmode.dri2_flipping) 280 return FALSE; 281 282 /* The kernel driver doesn't handle flipping between BOs with different 283 * tiling parameters correctly yet 284 */ 285 screen_pixmap = screen->GetScreenPixmap(screen); 286 if (radeon_present_get_pixmap_tiling_flags(info, pixmap) != 287 radeon_present_get_pixmap_tiling_flags(info, screen_pixmap)) 288 return FALSE; 289 290 return radeon_present_check_unflip(scrn); 291} 292 293/* 294 * Once the flip has been completed on all CRTCs, notify the 295 * extension code telling it when that happened 296 */ 297static void 298radeon_present_flip_event(xf86CrtcPtr crtc, uint32_t msc, uint64_t ust, void *pageflip_data) 299{ 300 RADEONInfoPtr info = RADEONPTR(crtc->scrn); 301 struct radeon_present_vblank_event *event = pageflip_data; 302 303 if (event->unflip) 304 info->drmmode.present_flipping = FALSE; 305 306 present_event_notify(event->event_id, ust, msc); 307 free(event); 308} 309 310/* 311 * The flip has been aborted, free the structure 312 */ 313static void 314radeon_present_flip_abort(xf86CrtcPtr crtc, void *pageflip_data) 315{ 316 struct radeon_present_vblank_event *event = pageflip_data; 317 318 free(event); 319} 320 321/* 322 * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true, 323 * then wait for vblank. Otherwise, flip immediately 324 */ 325static Bool 326radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, 327 PixmapPtr pixmap, Bool sync_flip) 328{ 329 ScreenPtr screen = crtc->pScreen; 330 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 331 RADEONInfoPtr info = RADEONPTR(scrn); 332 struct radeon_present_vblank_event *event; 333 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 334 int crtc_id = xf86_crtc ? drmmode_get_crtc_id(xf86_crtc) : -1; 335 uint32_t handle; 336 Bool ret; 337 338 if (!radeon_present_check_flip(crtc, screen->root, pixmap, sync_flip)) 339 return FALSE; 340 341 if (!radeon_get_pixmap_handle(pixmap, &handle)) 342 return FALSE; 343 344 event = calloc(1, sizeof(struct radeon_present_vblank_event)); 345 if (!event) 346 return FALSE; 347 348 event->event_id = event_id; 349 350 radeon_cs_flush_indirect(scrn); 351 352 ret = radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, handle, 353 event_id, event, crtc_id, 354 radeon_present_flip_event, 355 radeon_present_flip_abort, 356 sync_flip ? FLIP_VSYNC : FLIP_ASYNC, 357 target_msc); 358 if (!ret) 359 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n"); 360 else 361 info->drmmode.present_flipping = TRUE; 362 363 return ret; 364} 365 366/* 367 * Queue a flip back to the normal frame buffer 368 */ 369static void 370radeon_present_unflip(ScreenPtr screen, uint64_t event_id) 371{ 372 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 373 RADEONInfoPtr info = RADEONPTR(scrn); 374 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 375 struct radeon_present_vblank_event *event; 376 PixmapPtr pixmap = screen->GetScreenPixmap(screen); 377 enum drmmode_flip_sync flip_sync = 378 (radeon_present_screen_info.capabilities & PresentCapabilityAsync) ? 379 FLIP_ASYNC : FLIP_VSYNC; 380 uint32_t handle; 381 int old_fb_id; 382 int i; 383 384 radeon_cs_flush_indirect(scrn); 385 386 if (!radeon_present_check_unflip(scrn)) 387 goto modeset; 388 389 if (!radeon_get_pixmap_handle(pixmap, &handle)) { 390 ErrorF("%s: radeon_get_pixmap_handle failed, display might freeze\n", 391 __func__); 392 goto modeset; 393 } 394 395 event = calloc(1, sizeof(struct radeon_present_vblank_event)); 396 if (!event) { 397 ErrorF("%s: calloc failed, display might freeze\n", __func__); 398 goto modeset; 399 } 400 401 event->event_id = event_id; 402 event->unflip = TRUE; 403 404 if (radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, handle, 405 event_id, event, -1, radeon_present_flip_event, 406 radeon_present_flip_abort, flip_sync, 0)) 407 return; 408 409modeset: 410 /* info->drmmode.fb_id still points to the FB for the last flipped BO. 411 * Clear it, drmmode_set_mode_major will re-create it 412 */ 413 old_fb_id = info->drmmode.fb_id; 414 info->drmmode.fb_id = 0; 415 416 radeon_bo_wait(info->front_bo); 417 for (i = 0; i < config->num_crtc; i++) { 418 xf86CrtcPtr crtc = config->crtc[i]; 419 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 420 421 if (!crtc->enabled) 422 continue; 423 424 if (drmmode_crtc->pending_dpms_mode == DPMSModeOn) 425 crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 426 crtc->x, crtc->y); 427 else 428 drmmode_crtc->need_modeset = TRUE; 429 } 430 431 drmModeRmFB(info->drmmode.fd, old_fb_id); 432 present_event_notify(event_id, 0, 0); 433 434 info->drmmode.present_flipping = FALSE; 435} 436 437static present_screen_info_rec radeon_present_screen_info = { 438 .version = 0, 439 440 .get_crtc = radeon_present_get_crtc, 441 .get_ust_msc = radeon_present_get_ust_msc, 442 .queue_vblank = radeon_present_queue_vblank, 443 .abort_vblank = radeon_present_abort_vblank, 444 .flush = radeon_present_flush, 445 446 .capabilities = PresentCapabilityNone, 447 .check_flip = radeon_present_check_flip, 448 .flip = radeon_present_flip, 449 .unflip = radeon_present_unflip, 450}; 451 452static Bool 453radeon_present_has_async_flip(ScreenPtr screen) 454{ 455#ifdef DRM_CAP_ASYNC_PAGE_FLIP 456 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 457 RADEONInfoPtr info = RADEONPTR(scrn); 458 int ret; 459 uint64_t value; 460 461 ret = drmGetCap(info->dri2.drm_fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); 462 if (ret == 0) 463 return value == 1; 464#endif 465 return FALSE; 466} 467 468Bool 469radeon_present_screen_init(ScreenPtr screen) 470{ 471 if (radeon_present_has_async_flip(screen)) 472 radeon_present_screen_info.capabilities |= PresentCapabilityAsync; 473 474 if (!present_screen_init(screen, &radeon_present_screen_info)) { 475 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_WARNING, 476 "Present extension disabled because present_screen_init failed\n"); 477 return FALSE; 478 } 479 480 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 481 "Present extension enabled\n"); 482 483 return TRUE; 484} 485 486#else /* !HAVE_PRESENT_H */ 487 488Bool 489radeon_present_screen_init(ScreenPtr screen) 490{ 491 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 492 "Present extension disabled because present.h not available at " 493 "build time\n"); 494 495 return FALSE; 496} 497 498#endif 499