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 uint32_t tiling, swizzle; 248 249 if (!scrn->vtSema) 250 return FALSE; 251 252 if (intel->shadow_present) 253 return FALSE; 254 255 if (!intel->use_pageflipping) 256 return FALSE; 257 258 if (crtc && !intel_crtc_on(crtc->devPrivate)) 259 return FALSE; 260 261 /* Check stride, can't change that on flip */ 262 if (pixmap->devKind != intel->front_pitch) 263 return FALSE; 264 265 /* Make sure there's a bo we can get to */ 266 bo = intel_get_pixmap_bo(pixmap); 267 if (!bo) 268 return FALSE; 269 270 if (drm_intel_bo_get_tiling(bo, &tiling, &swizzle)) 271 return FALSE; 272 273 if (tiling == I915_TILING_Y) 274 return FALSE; 275 276 return TRUE; 277} 278 279/* 280 * Once the flip has been completed on all pipes, notify the 281 * extension code telling it when that happened 282 */ 283static void 284intel_present_flip_event(uint64_t msc, uint64_t ust, void *pageflip_data) 285{ 286 struct intel_present_vblank_event *event = pageflip_data; 287 288 present_event_notify(event->event_id, ust, msc); 289 free(event); 290} 291 292/* 293 * The flip has been aborted, free the structure 294 */ 295static void 296intel_present_flip_abort(void *pageflip_data) 297{ 298 struct intel_present_vblank_event *event = pageflip_data; 299 300 free(event); 301} 302 303/* 304 * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true, 305 * then wait for vblank. Otherwise, flip immediately 306 */ 307static Bool 308intel_present_flip(RRCrtcPtr crtc, 309 uint64_t event_id, 310 uint64_t target_msc, 311 PixmapPtr pixmap, 312 Bool sync_flip) 313{ 314 ScreenPtr screen = crtc->pScreen; 315 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 316 intel_screen_private *intel = intel_get_screen_private(scrn); 317 struct intel_present_vblank_event *event; 318 int pipe = intel_present_crtc_pipe(screen, crtc); 319 dri_bo *bo; 320 Bool ret; 321 322 if (!intel_present_check_flip(crtc, screen->root, pixmap, sync_flip)) 323 return FALSE; 324 325 bo = intel_get_pixmap_bo(pixmap); 326 if (!bo) 327 return FALSE; 328 329 event = calloc(1, sizeof(struct intel_present_vblank_event)); 330 if (!event) 331 return FALSE; 332 333 event->event_id = event_id; 334 335 ret = intel_do_pageflip(intel, bo, pipe, !sync_flip, 336 event, 337 intel_present_flip_event, 338 intel_present_flip_abort); 339 if (!ret) 340 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 341 "present flip failed\n"); 342 return ret; 343} 344 345/* 346 * Queue a flip back to the normal frame buffer 347 */ 348static void 349intel_present_unflip(ScreenPtr screen, uint64_t event_id) 350{ 351 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 352 intel_screen_private *intel = intel_get_screen_private(scrn); 353 PixmapPtr pixmap = screen->GetScreenPixmap(screen); 354 struct intel_present_vblank_event *event = NULL; 355 dri_bo *bo; 356 357 if (!intel_present_check_flip(NULL, screen->root, pixmap, true)) 358 goto fail; 359 360 bo = intel_get_pixmap_bo(pixmap); 361 if (!bo) 362 goto fail; 363 364 event = calloc(1, sizeof(struct intel_present_vblank_event)); 365 if (!event) 366 goto fail; 367 368 event->event_id = event_id; 369 370 if (!intel_do_pageflip(intel, bo, -1, FALSE, event, 371 intel_present_flip_event, 372 intel_present_flip_abort)) 373 goto fail; 374 375 return; 376fail: 377 xf86SetDesiredModes(scrn); 378 present_event_notify(event_id, 0, 0); 379 free(event); 380} 381 382static present_screen_info_rec intel_present_screen_info = { 383 .version = PRESENT_SCREEN_INFO_VERSION, 384 385 .get_crtc = intel_present_get_crtc, 386 .get_ust_msc = intel_present_get_ust_msc, 387 .queue_vblank = intel_present_queue_vblank, 388 .abort_vblank = intel_present_abort_vblank, 389 .flush = intel_present_flush, 390 391 .capabilities = PresentCapabilityNone, 392 .check_flip = intel_present_check_flip, 393 .flip = intel_present_flip, 394 .unflip = intel_present_unflip, 395}; 396 397static Bool 398intel_present_has_async_flip(ScreenPtr screen) 399{ 400#ifdef DRM_CAP_ASYNC_PAGE_FLIP 401 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 402 intel_screen_private *intel = intel_get_screen_private(scrn); 403 int ret; 404 uint64_t value; 405 406 ret = drmGetCap(intel->drmSubFD, DRM_CAP_ASYNC_PAGE_FLIP, &value); 407 if (ret == 0) 408 return value == 1; 409#endif 410 return FALSE; 411} 412 413Bool 414intel_present_screen_init(ScreenPtr screen) 415{ 416 if (intel_present_has_async_flip(screen)) 417 intel_present_screen_info.capabilities |= PresentCapabilityAsync; 418 419 return present_screen_init(screen, &intel_present_screen_info); 420} 421