diff options
author | Eric Anholt <eric@anholt.net> | 2014-10-10 11:36:19 +0200 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2014-10-15 10:36:05 +0100 |
commit | 4a60c93cc167af2822b847a7728471214db49ad9 (patch) | |
tree | c7076410e1d7759d2d715f7f5431ea90ec6271d5 | |
parent | 5be308a1761e56d314267c994516f18e2cda61c0 (diff) |
modesetting: Add support for the Present extensionmodesetting-present-no-pageflip
Like the DRI2 support, this doesn't have pageflipping for now.
-rw-r--r-- | hw/xfree86/drivers/modesetting/Makefile.am | 1 | ||||
-rw-r--r-- | hw/xfree86/drivers/modesetting/driver.h | 4 | ||||
-rw-r--r-- | hw/xfree86/drivers/modesetting/present.c | 266 | ||||
-rw-r--r-- | hw/xfree86/drivers/modesetting/vblank.c | 36 |
4 files changed, 307 insertions, 0 deletions
diff --git a/hw/xfree86/drivers/modesetting/Makefile.am b/hw/xfree86/drivers/modesetting/Makefile.am index 5b08600c1..4c5c0b677 100644 --- a/hw/xfree86/drivers/modesetting/Makefile.am +++ b/hw/xfree86/drivers/modesetting/Makefile.am @@ -48,6 +48,7 @@ modesetting_drv_la_SOURCES = \ driver.h \ drmmode_display.c \ drmmode_display.h \ + present.c \ vblank.c \ $(NULL) diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 9eda1c4da..2c275eb89 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -122,3 +122,7 @@ void ms_dri2_close_screen(ScreenPtr screen); Bool ms_vblank_screen_init(ScreenPtr screen); void ms_vblank_close_screen(ScreenPtr screen); +int ms_vblank_read_drm_events(ScrnInfoPtr scrn); +void ms_vblank_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data); + +Bool ms_present_screen_init(ScreenPtr screen); diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c new file mode 100644 index 000000000..f2bd8c0b8 --- /dev/null +++ b/hw/xfree86/drivers/modesetting/present.c @@ -0,0 +1,266 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include "dix-config.h" +#endif + +#ifdef PRESENT + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/time.h> +#include <time.h> +#include <errno.h> + +#include "xf86.h" +#include "xf86_OSproc.h" + +#include "xf86Pci.h" +#include "xf86drm.h" + +#include "windowstr.h" +#include "shadow.h" +#include "fb.h" +#include "present.h" +#ifdef GLAMOR +#include "glamor.h" +#endif + +#include "driver.h" + +static Bool debug; + +struct ms_present_vblank_event { + uint64_t event_id; +}; + +static RRCrtcPtr +ms_present_get_crtc(WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); + BoxRec box, crtcbox; + xf86CrtcPtr crtc; + RRCrtcPtr randr_crtc = NULL; + + box.x1 = window->drawable.x; + box.y1 = window->drawable.y; + box.x2 = box.x1 + window->drawable.width; + box.y2 = box.y1 + window->drawable.height; + + crtc = ms_covering_crtc(pScrn, &box, NULL, &crtcbox); + + /* Make sure the CRTC is valid and this is the real front buffer */ + if (crtc != NULL && !crtc->rotatedData) + randr_crtc = crtc->randr_crtc; + + return randr_crtc; +} + +static int +ms_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc) +{ + xf86CrtcPtr xf86_crtc = crtc->devPrivate; + + return ms_get_crtc_ust_msc(xf86_crtc, msc, ust); +} + +/* + * Called when the queued vblank event has occurred + */ +static void +ms_present_vblank_handler(uint64_t msc, uint64_t usec, void *data) +{ + struct ms_present_vblank_event *event = data; + + present_event_notify(event->event_id, usec, msc); + free(event); +} + +/* + * Called when the queued vblank is aborted + */ +static void +ms_present_vblank_abort(void *data) +{ + struct ms_present_vblank_event *event = data; + + free(event); +} + +/* + * Queue an event to report back to the Present extension when the + * specified MSC has passed. + */ +static int +ms_present_queue_vblank(RRCrtcPtr crtc, + uint64_t event_id, + uint64_t msc) +{ + xf86CrtcPtr xf86_crtc = crtc->devPrivate; + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; + ScreenPtr screen = crtc->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + struct ms_present_vblank_event *event; + drmVBlank vbl; + int ret; + uint32_t seq; + + event = calloc(sizeof(struct ms_present_vblank_event), 1); + if (!event) + return BadAlloc; + event->event_id = event_id; + seq = ms_drm_queue_alloc(xf86_crtc, event, + ms_present_vblank_handler, + ms_present_vblank_abort); + if (!seq) { + free(event); + return BadAlloc; + } + + vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | drmmode_crtc->vblank_pipe; + vbl.request.sequence = ms_crtc_msc_to_kernel_msc(xf86_crtc, msc); + vbl.request.signal = seq; + for (;;) { + ret = drmWaitVBlank(ms->fd, &vbl); + if (!ret) + break; + + /* If the ioctl returned EBUSY, it may be that we just need to + * flush the limited event queue. + */ + if (errno != EBUSY || !ms_vblank_read_drm_events(scrn)) + return BadAlloc; + } + if (debug) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, "\t\tiq %lld seq %u msc %llu (hw msc %u)\n", + (long long) event_id, seq, (long long) msc, vbl.request.sequence); + } + + return Success; +} + +static Bool +ms_present_event_match(void *data, void *match_data) +{ + struct ms_present_vblank_event *event = data; + uint64_t *match = match_data; + + return *match == event->event_id; +} + +/* + * Remove a pending vblank event from the DRM queue so that it is not reported + * to the extension + */ +static void +ms_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) +{ + ScreenPtr screen = crtc->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + + ms_vblank_abort(scrn, ms_present_event_match, &event_id); +} + +/* + * Flush our batch buffer when requested by the Present extension. + */ +static void +ms_present_flush(WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + +#ifdef GLAMOR + if (ms->glamor) + glamor_block_handler(screen); +#endif +} + +/* + * Test to see if page flipping is possible on the target crtc + */ +static Bool +ms_present_check_flip(RRCrtcPtr crtc, + WindowPtr window, + PixmapPtr pixmap, + Bool sync_flip) +{ + /* We don't do pageflipping yet. */ + return FALSE; +} + +/* + * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true, + * then wait for vblank. Otherwise, flip immediately + */ +static Bool +ms_present_flip(RRCrtcPtr crtc, + uint64_t event_id, + uint64_t target_msc, + PixmapPtr pixmap, + Bool sync_flip) +{ + ErrorF("%s should not have been called\n", __func__); + return FALSE; +} + +/* + * Queue a flip back to the normal frame buffer + */ +static void +ms_present_unflip(ScreenPtr screen, uint64_t event_id) +{ + ErrorF("%s should not have been called\n", __func__); +} + +static present_screen_info_rec ms_present_screen_info = { + .version = PRESENT_SCREEN_INFO_VERSION, + + .get_crtc = ms_present_get_crtc, + .get_ust_msc = ms_present_get_ust_msc, + .queue_vblank = ms_present_queue_vblank, + .abort_vblank = ms_present_abort_vblank, + .flush = ms_present_flush, + + .capabilities = PresentCapabilityNone, + .check_flip = ms_present_check_flip, + .flip = ms_present_flip, + .unflip = ms_present_unflip, +}; + +Bool +ms_present_screen_init(ScreenPtr screen) +{ + return present_screen_init(screen, &ms_present_screen_info); +} + +#endif /* PRESENT */ diff --git a/hw/xfree86/drivers/modesetting/vblank.c b/hw/xfree86/drivers/modesetting/vblank.c index 1c495ccce..1f2bb3226 100644 --- a/hw/xfree86/drivers/modesetting/vblank.c +++ b/hw/xfree86/drivers/modesetting/vblank.c @@ -323,6 +323,23 @@ ms_drm_abort_scrn(ScrnInfoPtr scrn) } /* + * Externally usable abort function that uses a callback to match a single queued + * entry to abort + */ +void +ms_vblank_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data) +{ + struct ms_drm_queue *q; + + xorg_list_for_each_entry(q, &ms_drm_queue, list) { + if (match(q->data, match_data)) { + ms_drm_abort_one(q); + break; + } + } +} + +/* * General DRM kernel handler. Looks for the matching sequence number in the * drm event queue and calls the handler for it. */ @@ -346,6 +363,25 @@ ms_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec, } } + +/** Consumes any pending DRM vblank events. */ +int +ms_vblank_read_drm_events(ScrnInfoPtr scrn) +{ + modesettingPtr ms = modesettingPTR(scrn); + struct pollfd p = { .fd = ms->fd, .events = POLLIN }; + int r; + + do { + r = poll(&p, 1, 0); + } while (r == -1 && (errno == EINTR || errno == EAGAIN)); + + if (r <= 0) + return 0; + + return drmHandleEvent(ms->fd, &ms->event_context); +} + Bool ms_vblank_screen_init(ScreenPtr screen) { |