radeon_present.c revision 39413783
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 if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 162 free(event); 163 return BadAlloc; 164 } 165 166 for (;;) { 167 if (drmmode_wait_vblank(xf86_crtc, 168 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT, msc, 169 drm_queue_seq, NULL, NULL)) 170 break; 171 if (errno != EBUSY || !radeon_present_flush_drm_events(screen)) { 172 radeon_drm_abort_entry(drm_queue_seq); 173 return BadAlloc; 174 } 175 } 176 177 return Success; 178} 179 180/* 181 * Remove a pending vblank event from the DRM queue so that it is not reported 182 * to the extension 183 */ 184static void 185radeon_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) 186{ 187 radeon_drm_abort_id(event_id); 188} 189 190/* 191 * Flush our batch buffer when requested by the Present extension. 192 */ 193static void 194radeon_present_flush(WindowPtr window) 195{ 196 radeon_cs_flush_indirect(xf86ScreenToScrn(window->drawable.pScreen)); 197} 198 199static uint32_t 200radeon_present_get_pixmap_tiling_flags(RADEONInfoPtr info, PixmapPtr pixmap) 201{ 202 uint32_t tiling_flags = radeon_get_pixmap_tiling_flags(pixmap); 203 204 /* Micro tiling is always enabled with macro tiling on >= R600, so we 205 * can ignore the micro tiling bit in that case 206 */ 207 if ((tiling_flags & RADEON_TILING_MACRO) && 208 info->ChipFamily >= CHIP_FAMILY_R600) 209 tiling_flags &= ~RADEON_TILING_MICRO; 210 211 return tiling_flags; 212} 213 214/* 215 * Test to see if unflipping is possible 216 * 217 * These tests have to pass for flips as well 218 */ 219static Bool 220radeon_present_check_unflip(ScrnInfoPtr scrn) 221{ 222 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 223 int num_crtcs_on; 224 int i; 225 226 if (!scrn->vtSema) 227 return FALSE; 228 229 for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { 230 xf86CrtcPtr crtc = config->crtc[i]; 231 232 if (drmmode_crtc_can_flip(crtc)) { 233 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 234 235 if (drmmode_crtc->flip_pending) 236 return FALSE; 237 238 if (!drmmode_crtc->tear_free) 239 num_crtcs_on++; 240 } 241 } 242 243 return num_crtcs_on > 0; 244} 245 246/* 247 * Test to see if page flipping is possible on the target crtc 248 */ 249static Bool 250radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, 251 Bool sync_flip) 252{ 253 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 254 ScreenPtr screen = window->drawable.pScreen; 255 ScrnInfoPtr scrn = xf86_crtc->scrn; 256 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 257 RADEONInfoPtr info = RADEONPTR(scrn); 258 PixmapPtr screen_pixmap; 259 int num_crtcs_on; 260 int i; 261 262 if (!scrn->vtSema) 263 return FALSE; 264 265 if (!info->allowPageFlip) 266 return FALSE; 267 268 if (info->sprites_visible > 0) 269 return FALSE; 270 271 if (info->drmmode.dri2_flipping) 272 return FALSE; 273 274 /* The kernel driver doesn't handle flipping between BOs with different 275 * tiling parameters correctly yet 276 */ 277 screen_pixmap = screen->GetScreenPixmap(screen); 278 if (radeon_present_get_pixmap_tiling_flags(info, pixmap) != 279 radeon_present_get_pixmap_tiling_flags(info, screen_pixmap)) 280 return FALSE; 281 282 for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { 283 if (drmmode_crtc_can_flip(config->crtc[i])) 284 num_crtcs_on++; 285 else if (config->crtc[i] == crtc->devPrivate) 286 return FALSE; 287 } 288 289 if (num_crtcs_on == 0) 290 return FALSE; 291 292 return TRUE; 293} 294 295/* 296 * Once the flip has been completed on all CRTCs, notify the 297 * extension code telling it when that happened 298 */ 299static void 300radeon_present_flip_event(xf86CrtcPtr crtc, uint32_t msc, uint64_t ust, void *pageflip_data) 301{ 302 RADEONInfoPtr info = RADEONPTR(crtc->scrn); 303 struct radeon_present_vblank_event *event = pageflip_data; 304 305 if (event->unflip) 306 info->drmmode.present_flipping = FALSE; 307 308 present_event_notify(event->event_id, ust, msc); 309 free(event); 310} 311 312/* 313 * The flip has been aborted, free the structure 314 */ 315static void 316radeon_present_flip_abort(xf86CrtcPtr crtc, void *pageflip_data) 317{ 318 struct radeon_present_vblank_event *event = pageflip_data; 319 320 free(event); 321} 322 323/* 324 * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true, 325 * then wait for vblank. Otherwise, flip immediately 326 */ 327static Bool 328radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, 329 PixmapPtr pixmap, Bool sync_flip) 330{ 331 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 332 ScreenPtr screen = crtc->pScreen; 333 ScrnInfoPtr scrn = xf86_crtc->scrn; 334 RADEONInfoPtr info = RADEONPTR(scrn); 335 struct radeon_present_vblank_event *event; 336 Bool ret = FALSE; 337 338 if (!radeon_present_check_flip(crtc, screen->root, pixmap, sync_flip)) 339 return ret; 340 341 event = calloc(1, sizeof(struct radeon_present_vblank_event)); 342 if (!event) 343 return ret; 344 345 event->event_id = event_id; 346 347 radeon_cs_flush_indirect(scrn); 348 349 ret = radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, pixmap, 350 event_id, event, crtc->devPrivate, 351 radeon_present_flip_event, 352 radeon_present_flip_abort, 353 sync_flip ? FLIP_VSYNC : FLIP_ASYNC, 354 target_msc); 355 if (!ret) 356 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n"); 357 else 358 info->drmmode.present_flipping = TRUE; 359 360 return ret; 361} 362 363/* 364 * Queue a flip back to the normal frame buffer 365 */ 366static void 367radeon_present_unflip(ScreenPtr screen, uint64_t event_id) 368{ 369 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 370 RADEONInfoPtr info = RADEONPTR(scrn); 371 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 372 struct radeon_present_vblank_event *event; 373 PixmapPtr pixmap = screen->GetScreenPixmap(screen); 374 enum drmmode_flip_sync flip_sync = 375 (radeon_present_screen_info.capabilities & PresentCapabilityAsync) ? 376 FLIP_ASYNC : FLIP_VSYNC; 377 int i; 378 379 if (!radeon_present_check_unflip(scrn)) 380 goto modeset; 381 382 event = calloc(1, sizeof(struct radeon_present_vblank_event)); 383 if (!event) { 384 ErrorF("%s: calloc failed, display might freeze\n", __func__); 385 goto modeset; 386 } 387 388 event->event_id = event_id; 389 event->unflip = TRUE; 390 391 if (radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, pixmap, 392 event_id, event, NULL, radeon_present_flip_event, 393 radeon_present_flip_abort, flip_sync, 0)) 394 return; 395 396modeset: 397 radeon_finish(scrn, info->front_buffer); 398 for (i = 0; i < config->num_crtc; i++) { 399 xf86CrtcPtr crtc = config->crtc[i]; 400 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 401 402 if (!crtc->enabled || drmmode_crtc->tear_free) 403 continue; 404 405 if (drmmode_crtc->dpms_mode == DPMSModeOn) 406 crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 407 crtc->x, crtc->y); 408 else 409 drmmode_crtc->need_modeset = TRUE; 410 } 411 412 present_event_notify(event_id, 0, 0); 413 414 info->drmmode.present_flipping = FALSE; 415} 416 417static present_screen_info_rec radeon_present_screen_info = { 418 .version = 0, 419 420 .get_crtc = radeon_present_get_crtc, 421 .get_ust_msc = radeon_present_get_ust_msc, 422 .queue_vblank = radeon_present_queue_vblank, 423 .abort_vblank = radeon_present_abort_vblank, 424 .flush = radeon_present_flush, 425 426 .capabilities = PresentCapabilityNone, 427 .check_flip = radeon_present_check_flip, 428 .flip = radeon_present_flip, 429 .unflip = radeon_present_unflip, 430}; 431 432static Bool 433radeon_present_has_async_flip(ScreenPtr screen) 434{ 435#ifdef DRM_CAP_ASYNC_PAGE_FLIP 436 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 437 RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 438 int ret; 439 uint64_t value; 440 441 ret = drmGetCap(pRADEONEnt->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); 442 if (ret == 0) 443 return value == 1; 444#endif 445 return FALSE; 446} 447 448Bool 449radeon_present_screen_init(ScreenPtr screen) 450{ 451 if (radeon_present_has_async_flip(screen)) 452 radeon_present_screen_info.capabilities |= PresentCapabilityAsync; 453 454 if (!present_screen_init(screen, &radeon_present_screen_info)) { 455 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_WARNING, 456 "Present extension disabled because present_screen_init failed\n"); 457 return FALSE; 458 } 459 460 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 461 "Present extension enabled\n"); 462 463 return TRUE; 464} 465 466#else /* !HAVE_PRESENT_H */ 467 468Bool 469radeon_present_screen_init(ScreenPtr screen) 470{ 471 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 472 "Present extension disabled because present.h not available at " 473 "build time\n"); 474 475 return FALSE; 476} 477 478#endif 479