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