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