142542f5fSchristos/* 242542f5fSchristos * Copyright © 2014 Intel Corporation 342542f5fSchristos * 442542f5fSchristos * Permission to use, copy, modify, distribute, and sell this software and its 542542f5fSchristos * documentation for any purpose is hereby granted without fee, provided that 642542f5fSchristos * the above copyright notice appear in all copies and that both that copyright 742542f5fSchristos * notice and this permission notice appear in supporting documentation, and 842542f5fSchristos * that the name of the copyright holders not be used in advertising or 942542f5fSchristos * publicity pertaining to distribution of the software without specific, 1042542f5fSchristos * written prior permission. The copyright holders make no representations 1142542f5fSchristos * about the suitability of this software for any purpose. It is provided "as 1242542f5fSchristos * is" without express or implied warranty. 1342542f5fSchristos * 1442542f5fSchristos * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1542542f5fSchristos * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1642542f5fSchristos * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1742542f5fSchristos * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1842542f5fSchristos * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1942542f5fSchristos * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2042542f5fSchristos * OF THIS SOFTWARE. 2142542f5fSchristos */ 2242542f5fSchristos 2342542f5fSchristos#ifdef HAVE_CONFIG_H 2442542f5fSchristos#include "config.h" 2542542f5fSchristos#endif 2642542f5fSchristos 2742542f5fSchristos#include <stdio.h> 2842542f5fSchristos#include <string.h> 2942542f5fSchristos#include <assert.h> 3042542f5fSchristos#include <sys/types.h> 3142542f5fSchristos#include <sys/stat.h> 3242542f5fSchristos#include <sys/ioctl.h> 3342542f5fSchristos#include <unistd.h> 3442542f5fSchristos#include <fcntl.h> 3542542f5fSchristos#include <sys/time.h> 3642542f5fSchristos#include <time.h> 3742542f5fSchristos#include <errno.h> 3842542f5fSchristos 3942542f5fSchristos#include "xorg-server.h" 4042542f5fSchristos#include "xf86.h" 4142542f5fSchristos#include "xf86_OSproc.h" 4242542f5fSchristos 4342542f5fSchristos#include "xf86Pci.h" 4442542f5fSchristos#include "xf86drm.h" 4542542f5fSchristos 4642542f5fSchristos#include "windowstr.h" 4742542f5fSchristos#include "shadow.h" 4842542f5fSchristos#include "fb.h" 4942542f5fSchristos 5042542f5fSchristos#include "intel.h" 5142542f5fSchristos#include "i830_reg.h" 5242542f5fSchristos 5342542f5fSchristos#include "i915_drm.h" 5442542f5fSchristos 5542542f5fSchristos#include "present.h" 5642542f5fSchristos 5742542f5fSchristosstruct intel_present_vblank_event { 5842542f5fSchristos uint64_t event_id; 5942542f5fSchristos}; 6042542f5fSchristos 6142542f5fSchristosstatic uint32_t pipe_select(int pipe) 6242542f5fSchristos{ 6342542f5fSchristos if (pipe > 1) 6442542f5fSchristos return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; 6542542f5fSchristos else if (pipe > 0) 6642542f5fSchristos return DRM_VBLANK_SECONDARY; 6742542f5fSchristos else 6842542f5fSchristos return 0; 6942542f5fSchristos} 7042542f5fSchristos 7142542f5fSchristosstatic RRCrtcPtr 7242542f5fSchristosintel_present_get_crtc(WindowPtr window) 7342542f5fSchristos{ 7442542f5fSchristos ScreenPtr screen = window->drawable.pScreen; 7542542f5fSchristos ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 7642542f5fSchristos BoxRec box, crtcbox; 7742542f5fSchristos xf86CrtcPtr crtc; 7842542f5fSchristos RRCrtcPtr randr_crtc = NULL; 7942542f5fSchristos 8042542f5fSchristos box.x1 = window->drawable.x; 8142542f5fSchristos box.y1 = window->drawable.y; 8242542f5fSchristos box.x2 = box.x1 + window->drawable.width; 8342542f5fSchristos box.y2 = box.y1 + window->drawable.height; 8442542f5fSchristos 8542542f5fSchristos crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox); 8642542f5fSchristos 8742542f5fSchristos /* Make sure the CRTC is valid and this is the real front buffer */ 8842542f5fSchristos if (crtc != NULL && !crtc->rotatedData) 8942542f5fSchristos randr_crtc = crtc->randr_crtc; 9042542f5fSchristos 9142542f5fSchristos return randr_crtc; 9242542f5fSchristos} 9342542f5fSchristos 9442542f5fSchristosstatic int 9542542f5fSchristosintel_present_crtc_pipe(ScreenPtr screen, RRCrtcPtr randr_crtc) 9642542f5fSchristos{ 9742542f5fSchristos xf86CrtcPtr crtc; 9842542f5fSchristos 9942542f5fSchristos if (randr_crtc == NULL) 10042542f5fSchristos return 0; 10142542f5fSchristos 10242542f5fSchristos crtc = randr_crtc->devPrivate; 10342542f5fSchristos return intel_crtc_to_pipe(crtc); 10442542f5fSchristos} 10542542f5fSchristos 10642542f5fSchristosstatic int 10742542f5fSchristosintel_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc) 10842542f5fSchristos{ 10942542f5fSchristos xf86CrtcPtr xf86_crtc = crtc->devPrivate; 11042542f5fSchristos ScreenPtr screen = crtc->pScreen; 11142542f5fSchristos ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 11242542f5fSchristos 11342542f5fSchristos return intel_get_crtc_msc_ust(scrn, xf86_crtc, msc, ust); 11442542f5fSchristos} 11542542f5fSchristos 11642542f5fSchristos/* 11742542f5fSchristos * Flush the DRM event queue when full; this 11842542f5fSchristos * makes space for new requests 11942542f5fSchristos */ 12042542f5fSchristosstatic Bool 12142542f5fSchristosintel_present_flush_drm_events(ScreenPtr screen) 12242542f5fSchristos{ 12342542f5fSchristos ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 12442542f5fSchristos intel_screen_private *intel = intel_get_screen_private(scrn); 12542542f5fSchristos 12642542f5fSchristos return intel_mode_read_drm_events(intel) >= 0; 12742542f5fSchristos} 12842542f5fSchristos 12942542f5fSchristos/* 13042542f5fSchristos * Called when the queued vblank event has occurred 13142542f5fSchristos */ 13242542f5fSchristosstatic void 13342542f5fSchristosintel_present_vblank_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t msc, uint64_t usec, void *data) 13442542f5fSchristos{ 13542542f5fSchristos struct intel_present_vblank_event *event = data; 13642542f5fSchristos 13742542f5fSchristos present_event_notify(event->event_id, usec, msc); 13842542f5fSchristos free(event); 13942542f5fSchristos} 14042542f5fSchristos 14142542f5fSchristos/* 14242542f5fSchristos * Called when the queued vblank is aborted 14342542f5fSchristos */ 14442542f5fSchristosstatic void 14542542f5fSchristosintel_present_vblank_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data) 14642542f5fSchristos{ 14742542f5fSchristos struct intel_present_vblank_event *event = data; 14842542f5fSchristos 14942542f5fSchristos free(event); 15042542f5fSchristos} 15142542f5fSchristos 15242542f5fSchristos/* 15342542f5fSchristos * Queue an event to report back to the Present extension when the specified 15442542f5fSchristos * MSC has past 15542542f5fSchristos */ 15642542f5fSchristosstatic int 15742542f5fSchristosintel_present_queue_vblank(RRCrtcPtr crtc, 15842542f5fSchristos uint64_t event_id, 15942542f5fSchristos uint64_t msc) 16042542f5fSchristos{ 16142542f5fSchristos xf86CrtcPtr xf86_crtc = crtc->devPrivate; 16242542f5fSchristos ScreenPtr screen = crtc->pScreen; 16342542f5fSchristos ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 16442542f5fSchristos intel_screen_private *intel = intel_get_screen_private(scrn); 16542542f5fSchristos int pipe = intel_present_crtc_pipe(screen, crtc); 16642542f5fSchristos struct intel_present_vblank_event *event; 16742542f5fSchristos drmVBlank vbl; 16842542f5fSchristos int ret; 16942542f5fSchristos uint32_t seq; 17042542f5fSchristos 17142542f5fSchristos event = calloc(sizeof(struct intel_present_vblank_event), 1); 17242542f5fSchristos if (!event) 17342542f5fSchristos return BadAlloc; 17442542f5fSchristos event->event_id = event_id; 17542542f5fSchristos seq = intel_drm_queue_alloc(scrn, xf86_crtc, event, 17642542f5fSchristos intel_present_vblank_handler, 17742542f5fSchristos intel_present_vblank_abort); 17842542f5fSchristos if (!seq) { 17942542f5fSchristos free(event); 18042542f5fSchristos return BadAlloc; 18142542f5fSchristos } 18242542f5fSchristos 18342542f5fSchristos vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 18442542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, xf86_crtc, msc); 18542542f5fSchristos vbl.request.signal = seq; 18642542f5fSchristos for (;;) { 18742542f5fSchristos ret = drmWaitVBlank(intel->drmSubFD, &vbl); 18842542f5fSchristos if (!ret) 18942542f5fSchristos break; 19042542f5fSchristos if (errno != EBUSY || !intel_present_flush_drm_events(screen)) 19142542f5fSchristos return BadAlloc; 19242542f5fSchristos } 19313496ba1Ssnj DebugPresent(("\t\tiq %lld seq %u msc %llu (hw msc %u)\n", 19413496ba1Ssnj (long long) event_id, seq, (long long) msc, vbl.request.sequence)); 19542542f5fSchristos return Success; 19642542f5fSchristos} 19742542f5fSchristos 19842542f5fSchristosstatic Bool 19942542f5fSchristosintel_present_event_match(void *data, void *match_data) 20042542f5fSchristos{ 20142542f5fSchristos struct intel_present_vblank_event *event = data; 20242542f5fSchristos uint64_t *match = match_data; 20342542f5fSchristos 20442542f5fSchristos return *match == event->event_id; 20542542f5fSchristos} 20642542f5fSchristos 20742542f5fSchristos/* 20842542f5fSchristos * Remove a pending vblank event from the DRM queue so that it is not reported 20942542f5fSchristos * to the extension 21042542f5fSchristos */ 21142542f5fSchristosstatic void 21242542f5fSchristosintel_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) 21342542f5fSchristos{ 21442542f5fSchristos ScreenPtr screen = crtc->pScreen; 21542542f5fSchristos ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 21642542f5fSchristos 21742542f5fSchristos intel_drm_abort(scrn, intel_present_event_match, &event_id); 21842542f5fSchristos} 21942542f5fSchristos 22042542f5fSchristos/* 22142542f5fSchristos * Flush our batch buffer when requested by the Present extension. 22242542f5fSchristos */ 22342542f5fSchristosstatic void 22442542f5fSchristosintel_present_flush(WindowPtr window) 22542542f5fSchristos{ 22642542f5fSchristos ScreenPtr screen = window->drawable.pScreen; 22742542f5fSchristos ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 22842542f5fSchristos intel_screen_private *intel = intel_get_screen_private(scrn); 22942542f5fSchristos 23042542f5fSchristos if (intel->flush_rendering) 23142542f5fSchristos intel->flush_rendering(intel); 23242542f5fSchristos} 23342542f5fSchristos 23442542f5fSchristos/* 23542542f5fSchristos * Test to see if page flipping is possible on the target crtc 23642542f5fSchristos */ 23742542f5fSchristosstatic Bool 23842542f5fSchristosintel_present_check_flip(RRCrtcPtr crtc, 23942542f5fSchristos WindowPtr window, 24042542f5fSchristos PixmapPtr pixmap, 24142542f5fSchristos Bool sync_flip) 24242542f5fSchristos{ 24342542f5fSchristos ScreenPtr screen = window->drawable.pScreen; 24442542f5fSchristos ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 24542542f5fSchristos intel_screen_private *intel = intel_get_screen_private(scrn); 24613496ba1Ssnj dri_bo *bo; 247fe8aea9eSmrg uint32_t tiling, swizzle; 24842542f5fSchristos 24942542f5fSchristos if (!scrn->vtSema) 25042542f5fSchristos return FALSE; 25142542f5fSchristos 25242542f5fSchristos if (intel->shadow_present) 25342542f5fSchristos return FALSE; 25442542f5fSchristos 25542542f5fSchristos if (!intel->use_pageflipping) 25642542f5fSchristos return FALSE; 25742542f5fSchristos 25842542f5fSchristos if (crtc && !intel_crtc_on(crtc->devPrivate)) 25942542f5fSchristos return FALSE; 26042542f5fSchristos 26113496ba1Ssnj /* Check stride, can't change that on flip */ 26213496ba1Ssnj if (pixmap->devKind != intel->front_pitch) 26313496ba1Ssnj return FALSE; 26413496ba1Ssnj 26513496ba1Ssnj /* Make sure there's a bo we can get to */ 26613496ba1Ssnj bo = intel_get_pixmap_bo(pixmap); 26713496ba1Ssnj if (!bo) 26813496ba1Ssnj return FALSE; 26913496ba1Ssnj 270fe8aea9eSmrg if (drm_intel_bo_get_tiling(bo, &tiling, &swizzle)) 271fe8aea9eSmrg return FALSE; 272fe8aea9eSmrg 273fe8aea9eSmrg if (tiling == I915_TILING_Y) 274fe8aea9eSmrg return FALSE; 275fe8aea9eSmrg 27642542f5fSchristos return TRUE; 27742542f5fSchristos} 27842542f5fSchristos 27942542f5fSchristos/* 28042542f5fSchristos * Once the flip has been completed on all pipes, notify the 28142542f5fSchristos * extension code telling it when that happened 28242542f5fSchristos */ 28342542f5fSchristosstatic void 28442542f5fSchristosintel_present_flip_event(uint64_t msc, uint64_t ust, void *pageflip_data) 28542542f5fSchristos{ 28642542f5fSchristos struct intel_present_vblank_event *event = pageflip_data; 28742542f5fSchristos 28842542f5fSchristos present_event_notify(event->event_id, ust, msc); 28942542f5fSchristos free(event); 29042542f5fSchristos} 29142542f5fSchristos 29242542f5fSchristos/* 29342542f5fSchristos * The flip has been aborted, free the structure 29442542f5fSchristos */ 29542542f5fSchristosstatic void 29642542f5fSchristosintel_present_flip_abort(void *pageflip_data) 29742542f5fSchristos{ 29842542f5fSchristos struct intel_present_vblank_event *event = pageflip_data; 29942542f5fSchristos 30042542f5fSchristos free(event); 30142542f5fSchristos} 30242542f5fSchristos 30342542f5fSchristos/* 30442542f5fSchristos * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true, 30542542f5fSchristos * then wait for vblank. Otherwise, flip immediately 30642542f5fSchristos */ 30742542f5fSchristosstatic Bool 30842542f5fSchristosintel_present_flip(RRCrtcPtr crtc, 30942542f5fSchristos uint64_t event_id, 31042542f5fSchristos uint64_t target_msc, 31142542f5fSchristos PixmapPtr pixmap, 31242542f5fSchristos Bool sync_flip) 31342542f5fSchristos{ 31442542f5fSchristos ScreenPtr screen = crtc->pScreen; 31542542f5fSchristos ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 31642542f5fSchristos intel_screen_private *intel = intel_get_screen_private(scrn); 31742542f5fSchristos struct intel_present_vblank_event *event; 31842542f5fSchristos int pipe = intel_present_crtc_pipe(screen, crtc); 31942542f5fSchristos dri_bo *bo; 32042542f5fSchristos Bool ret; 32142542f5fSchristos 32242542f5fSchristos if (!intel_present_check_flip(crtc, screen->root, pixmap, sync_flip)) 32342542f5fSchristos return FALSE; 32442542f5fSchristos 32542542f5fSchristos bo = intel_get_pixmap_bo(pixmap); 32642542f5fSchristos if (!bo) 32742542f5fSchristos return FALSE; 32842542f5fSchristos 32942542f5fSchristos event = calloc(1, sizeof(struct intel_present_vblank_event)); 33042542f5fSchristos if (!event) 33142542f5fSchristos return FALSE; 33242542f5fSchristos 33342542f5fSchristos event->event_id = event_id; 33442542f5fSchristos 33542542f5fSchristos ret = intel_do_pageflip(intel, bo, pipe, !sync_flip, 33642542f5fSchristos event, 33742542f5fSchristos intel_present_flip_event, 33842542f5fSchristos intel_present_flip_abort); 33942542f5fSchristos if (!ret) 34042542f5fSchristos xf86DrvMsg(scrn->scrnIndex, X_ERROR, 34142542f5fSchristos "present flip failed\n"); 34242542f5fSchristos return ret; 34342542f5fSchristos} 34442542f5fSchristos 34542542f5fSchristos/* 34642542f5fSchristos * Queue a flip back to the normal frame buffer 34742542f5fSchristos */ 34842542f5fSchristosstatic void 34942542f5fSchristosintel_present_unflip(ScreenPtr screen, uint64_t event_id) 35042542f5fSchristos{ 35142542f5fSchristos ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 35242542f5fSchristos intel_screen_private *intel = intel_get_screen_private(scrn); 35342542f5fSchristos PixmapPtr pixmap = screen->GetScreenPixmap(screen); 354fe8aea9eSmrg struct intel_present_vblank_event *event = NULL; 35542542f5fSchristos dri_bo *bo; 35642542f5fSchristos 35742542f5fSchristos if (!intel_present_check_flip(NULL, screen->root, pixmap, true)) 358fe8aea9eSmrg goto fail; 35942542f5fSchristos 36042542f5fSchristos bo = intel_get_pixmap_bo(pixmap); 36142542f5fSchristos if (!bo) 362fe8aea9eSmrg goto fail; 36342542f5fSchristos 36442542f5fSchristos event = calloc(1, sizeof(struct intel_present_vblank_event)); 36542542f5fSchristos if (!event) 366fe8aea9eSmrg goto fail; 36742542f5fSchristos 36842542f5fSchristos event->event_id = event_id; 36942542f5fSchristos 370fe8aea9eSmrg if (!intel_do_pageflip(intel, bo, -1, FALSE, event, 371fe8aea9eSmrg intel_present_flip_event, 372fe8aea9eSmrg intel_present_flip_abort)) 373fe8aea9eSmrg goto fail; 374fe8aea9eSmrg 375fe8aea9eSmrg return; 376fe8aea9eSmrgfail: 377fe8aea9eSmrg xf86SetDesiredModes(scrn); 378fe8aea9eSmrg present_event_notify(event_id, 0, 0); 379fe8aea9eSmrg free(event); 38042542f5fSchristos} 38142542f5fSchristos 38242542f5fSchristosstatic present_screen_info_rec intel_present_screen_info = { 38342542f5fSchristos .version = PRESENT_SCREEN_INFO_VERSION, 38442542f5fSchristos 38542542f5fSchristos .get_crtc = intel_present_get_crtc, 38642542f5fSchristos .get_ust_msc = intel_present_get_ust_msc, 38742542f5fSchristos .queue_vblank = intel_present_queue_vblank, 38842542f5fSchristos .abort_vblank = intel_present_abort_vblank, 38942542f5fSchristos .flush = intel_present_flush, 39042542f5fSchristos 39142542f5fSchristos .capabilities = PresentCapabilityNone, 39242542f5fSchristos .check_flip = intel_present_check_flip, 39342542f5fSchristos .flip = intel_present_flip, 39442542f5fSchristos .unflip = intel_present_unflip, 39542542f5fSchristos}; 39642542f5fSchristos 39742542f5fSchristosstatic Bool 39842542f5fSchristosintel_present_has_async_flip(ScreenPtr screen) 39942542f5fSchristos{ 40042542f5fSchristos#ifdef DRM_CAP_ASYNC_PAGE_FLIP 40142542f5fSchristos ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 40242542f5fSchristos intel_screen_private *intel = intel_get_screen_private(scrn); 40342542f5fSchristos int ret; 40442542f5fSchristos uint64_t value; 40542542f5fSchristos 40642542f5fSchristos ret = drmGetCap(intel->drmSubFD, DRM_CAP_ASYNC_PAGE_FLIP, &value); 40742542f5fSchristos if (ret == 0) 40842542f5fSchristos return value == 1; 40942542f5fSchristos#endif 41042542f5fSchristos return FALSE; 41142542f5fSchristos} 41242542f5fSchristos 41342542f5fSchristosBool 41442542f5fSchristosintel_present_screen_init(ScreenPtr screen) 41542542f5fSchristos{ 41642542f5fSchristos if (intel_present_has_async_flip(screen)) 41742542f5fSchristos intel_present_screen_info.capabilities |= PresentCapabilityAsync; 41842542f5fSchristos 41942542f5fSchristos return present_screen_init(screen, &intel_present_screen_info); 42042542f5fSchristos} 421