intel_present.c revision 13496ba1
1/* 2 * Copyright © 2014 Intel Corporation 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#ifdef HAVE_CONFIG_H 24#include "config.h" 25#endif 26 27#include <stdio.h> 28#include <string.h> 29#include <assert.h> 30#include <sys/types.h> 31#include <sys/stat.h> 32#include <sys/ioctl.h> 33#include <unistd.h> 34#include <fcntl.h> 35#include <sys/time.h> 36#include <time.h> 37#include <errno.h> 38 39#include "xorg-server.h" 40#include "xf86.h" 41#include "xf86_OSproc.h" 42 43#include "xf86Pci.h" 44#include "xf86drm.h" 45 46#include "windowstr.h" 47#include "shadow.h" 48#include "fb.h" 49 50#include "intel.h" 51#include "i830_reg.h" 52 53#include "i915_drm.h" 54 55#include "present.h" 56 57struct intel_present_vblank_event { 58 uint64_t event_id; 59}; 60 61static uint32_t pipe_select(int pipe) 62{ 63 if (pipe > 1) 64 return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; 65 else if (pipe > 0) 66 return DRM_VBLANK_SECONDARY; 67 else 68 return 0; 69} 70 71static RRCrtcPtr 72intel_present_get_crtc(WindowPtr window) 73{ 74 ScreenPtr screen = window->drawable.pScreen; 75 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 76 BoxRec box, crtcbox; 77 xf86CrtcPtr crtc; 78 RRCrtcPtr randr_crtc = NULL; 79 80 box.x1 = window->drawable.x; 81 box.y1 = window->drawable.y; 82 box.x2 = box.x1 + window->drawable.width; 83 box.y2 = box.y1 + window->drawable.height; 84 85 crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox); 86 87 /* Make sure the CRTC is valid and this is the real front buffer */ 88 if (crtc != NULL && !crtc->rotatedData) 89 randr_crtc = crtc->randr_crtc; 90 91 return randr_crtc; 92} 93 94static int 95intel_present_crtc_pipe(ScreenPtr screen, RRCrtcPtr randr_crtc) 96{ 97 xf86CrtcPtr crtc; 98 99 if (randr_crtc == NULL) 100 return 0; 101 102 crtc = randr_crtc->devPrivate; 103 return intel_crtc_to_pipe(crtc); 104} 105 106static int 107intel_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc) 108{ 109 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 110 ScreenPtr screen = crtc->pScreen; 111 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 112 113 return intel_get_crtc_msc_ust(scrn, xf86_crtc, msc, ust); 114} 115 116/* 117 * Flush the DRM event queue when full; this 118 * makes space for new requests 119 */ 120static Bool 121intel_present_flush_drm_events(ScreenPtr screen) 122{ 123 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 124 intel_screen_private *intel = intel_get_screen_private(scrn); 125 126 return intel_mode_read_drm_events(intel) >= 0; 127} 128 129/* 130 * Called when the queued vblank event has occurred 131 */ 132static void 133intel_present_vblank_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t msc, uint64_t usec, void *data) 134{ 135 struct intel_present_vblank_event *event = data; 136 137 present_event_notify(event->event_id, usec, msc); 138 free(event); 139} 140 141/* 142 * Called when the queued vblank is aborted 143 */ 144static void 145intel_present_vblank_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data) 146{ 147 struct intel_present_vblank_event *event = data; 148 149 free(event); 150} 151 152/* 153 * Queue an event to report back to the Present extension when the specified 154 * MSC has past 155 */ 156static int 157intel_present_queue_vblank(RRCrtcPtr crtc, 158 uint64_t event_id, 159 uint64_t msc) 160{ 161 xf86CrtcPtr xf86_crtc = crtc->devPrivate; 162 ScreenPtr screen = crtc->pScreen; 163 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 164 intel_screen_private *intel = intel_get_screen_private(scrn); 165 int pipe = intel_present_crtc_pipe(screen, crtc); 166 struct intel_present_vblank_event *event; 167 drmVBlank vbl; 168 int ret; 169 uint32_t seq; 170 171 event = calloc(sizeof(struct intel_present_vblank_event), 1); 172 if (!event) 173 return BadAlloc; 174 event->event_id = event_id; 175 seq = intel_drm_queue_alloc(scrn, xf86_crtc, event, 176 intel_present_vblank_handler, 177 intel_present_vblank_abort); 178 if (!seq) { 179 free(event); 180 return BadAlloc; 181 } 182 183 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 184 vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, xf86_crtc, msc); 185 vbl.request.signal = seq; 186 for (;;) { 187 ret = drmWaitVBlank(intel->drmSubFD, &vbl); 188 if (!ret) 189 break; 190 if (errno != EBUSY || !intel_present_flush_drm_events(screen)) 191 return BadAlloc; 192 } 193 DebugPresent(("\t\tiq %lld seq %u msc %llu (hw msc %u)\n", 194 (long long) event_id, seq, (long long) msc, vbl.request.sequence)); 195 return Success; 196} 197 198static Bool 199intel_present_event_match(void *data, void *match_data) 200{ 201 struct intel_present_vblank_event *event = data; 202 uint64_t *match = match_data; 203 204 return *match == event->event_id; 205} 206 207/* 208 * Remove a pending vblank event from the DRM queue so that it is not reported 209 * to the extension 210 */ 211static void 212intel_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) 213{ 214 ScreenPtr screen = crtc->pScreen; 215 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 216 217 intel_drm_abort(scrn, intel_present_event_match, &event_id); 218} 219 220/* 221 * Flush our batch buffer when requested by the Present extension. 222 */ 223static void 224intel_present_flush(WindowPtr window) 225{ 226 ScreenPtr screen = window->drawable.pScreen; 227 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 228 intel_screen_private *intel = intel_get_screen_private(scrn); 229 230 if (intel->flush_rendering) 231 intel->flush_rendering(intel); 232} 233 234/* 235 * Test to see if page flipping is possible on the target crtc 236 */ 237static Bool 238intel_present_check_flip(RRCrtcPtr crtc, 239 WindowPtr window, 240 PixmapPtr pixmap, 241 Bool sync_flip) 242{ 243 ScreenPtr screen = window->drawable.pScreen; 244 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 245 intel_screen_private *intel = intel_get_screen_private(scrn); 246 dri_bo *bo; 247 248 if (!scrn->vtSema) 249 return FALSE; 250 251 if (intel->shadow_present) 252 return FALSE; 253 254 if (!intel->use_pageflipping) 255 return FALSE; 256 257 if (crtc && !intel_crtc_on(crtc->devPrivate)) 258 return FALSE; 259 260 /* Check stride, can't change that on flip */ 261 if (pixmap->devKind != intel->front_pitch) 262 return FALSE; 263 264 /* Make sure there's a bo we can get to */ 265 bo = intel_get_pixmap_bo(pixmap); 266 if (!bo) 267 return FALSE; 268 269 return TRUE; 270} 271 272/* 273 * Once the flip has been completed on all pipes, notify the 274 * extension code telling it when that happened 275 */ 276static void 277intel_present_flip_event(uint64_t msc, uint64_t ust, void *pageflip_data) 278{ 279 struct intel_present_vblank_event *event = pageflip_data; 280 281 present_event_notify(event->event_id, ust, msc); 282 free(event); 283} 284 285/* 286 * The flip has been aborted, free the structure 287 */ 288static void 289intel_present_flip_abort(void *pageflip_data) 290{ 291 struct intel_present_vblank_event *event = pageflip_data; 292 293 free(event); 294} 295 296/* 297 * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true, 298 * then wait for vblank. Otherwise, flip immediately 299 */ 300static Bool 301intel_present_flip(RRCrtcPtr crtc, 302 uint64_t event_id, 303 uint64_t target_msc, 304 PixmapPtr pixmap, 305 Bool sync_flip) 306{ 307 ScreenPtr screen = crtc->pScreen; 308 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 309 intel_screen_private *intel = intel_get_screen_private(scrn); 310 struct intel_present_vblank_event *event; 311 int pipe = intel_present_crtc_pipe(screen, crtc); 312 dri_bo *bo; 313 Bool ret; 314 315 if (!intel_present_check_flip(crtc, screen->root, pixmap, sync_flip)) 316 return FALSE; 317 318 bo = intel_get_pixmap_bo(pixmap); 319 if (!bo) 320 return FALSE; 321 322 event = calloc(1, sizeof(struct intel_present_vblank_event)); 323 if (!event) 324 return FALSE; 325 326 event->event_id = event_id; 327 328 ret = intel_do_pageflip(intel, bo, pipe, !sync_flip, 329 event, 330 intel_present_flip_event, 331 intel_present_flip_abort); 332 if (!ret) 333 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 334 "present flip failed\n"); 335 return ret; 336} 337 338/* 339 * Queue a flip back to the normal frame buffer 340 */ 341static void 342intel_present_unflip(ScreenPtr screen, uint64_t event_id) 343{ 344 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 345 intel_screen_private *intel = intel_get_screen_private(scrn); 346 struct intel_present_vblank_event *event; 347 PixmapPtr pixmap = screen->GetScreenPixmap(screen); 348 dri_bo *bo; 349 Bool ret; 350 351 if (!intel_present_check_flip(NULL, screen->root, pixmap, true)) 352 return; 353 354 bo = intel_get_pixmap_bo(pixmap); 355 if (!bo) 356 return; 357 358 event = calloc(1, sizeof(struct intel_present_vblank_event)); 359 if (!event) 360 return; 361 362 event->event_id = event_id; 363 364 ret = intel_do_pageflip(intel, bo, -1, FALSE, event, intel_present_flip_event, intel_present_flip_abort); 365 if (!ret) { 366 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 367 "present unflip failed\n"); 368 } 369} 370 371static present_screen_info_rec intel_present_screen_info = { 372 .version = PRESENT_SCREEN_INFO_VERSION, 373 374 .get_crtc = intel_present_get_crtc, 375 .get_ust_msc = intel_present_get_ust_msc, 376 .queue_vblank = intel_present_queue_vblank, 377 .abort_vblank = intel_present_abort_vblank, 378 .flush = intel_present_flush, 379 380 .capabilities = PresentCapabilityNone, 381 .check_flip = intel_present_check_flip, 382 .flip = intel_present_flip, 383 .unflip = intel_present_unflip, 384}; 385 386static Bool 387intel_present_has_async_flip(ScreenPtr screen) 388{ 389#ifdef DRM_CAP_ASYNC_PAGE_FLIP 390 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 391 intel_screen_private *intel = intel_get_screen_private(scrn); 392 int ret; 393 uint64_t value; 394 395 ret = drmGetCap(intel->drmSubFD, DRM_CAP_ASYNC_PAGE_FLIP, &value); 396 if (ret == 0) 397 return value == 1; 398#endif 399 return FALSE; 400} 401 402Bool 403intel_present_screen_init(ScreenPtr screen) 404{ 405 if (intel_present_has_async_flip(screen)) 406 intel_present_screen_info.capabilities |= PresentCapabilityAsync; 407 408 return present_screen_init(screen, &intel_present_screen_info); 409} 410