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