summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-11-18 14:42:02 +1000
committerBen Skeggs <bskeggs@redhat.com>2014-06-20 14:29:32 +1000
commit882ebb4000803f6025e1bb3213a31b19f6d1a2c6 (patch)
treefa0acb993dcee78bb42d000d0acb9c5378ea2e23
parent0d94f32fce2759c4b0f4d22b99f3ced09c2aa5a0 (diff)
downloadxorg-driver-xf86-video-nouveau-882ebb4000803f6025e1bb3213a31b19f6d1a2c6.tar.gz
present: initial support
Until glamor grows its own implementation. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--src/Makefile.am4
-rw-r--r--src/nouveau_glamor.c2
-rw-r--r--src/nouveau_glamor.h3
-rw-r--r--src/nouveau_present.c350
-rw-r--r--src/nouveau_present.h15
-rw-r--r--src/nv_driver.c3
-rw-r--r--src/nv_type.h3
7 files changed, 378 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index a787db0..9d39a00 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,8 +36,9 @@ nouveau_drv_la_SOURCES = \
nouveau_copya0b5.c \
nouveau_exa.c nouveau_xv.c nouveau_dri2.c \
nouveau_glamor.c \
- nouveau_wfb.c \
+ nouveau_present.c \
nouveau_sync.c \
+ nouveau_wfb.c \
nv_accel_common.c \
nv_driver.c \
nv_shadow.c \
@@ -123,6 +124,7 @@ EXTRA_DIST = hwdefs/nv_3ddefs.xml.h \
nouveau_local.h \
nouveau_copy.h \
nouveau_glamor.h \
+ nouveau_present.h \
nouveau_sync.h \
nv_const.h \
nv_dma.h \
diff --git a/src/nouveau_glamor.c b/src/nouveau_glamor.c
index 9c88e77..ec6ebf9 100644
--- a/src/nouveau_glamor.c
+++ b/src/nouveau_glamor.c
@@ -27,7 +27,7 @@
static DevPrivateKeyRec glamor_private;
-static inline void
+void
nouveau_glamor_pixmap_set(PixmapPtr pixmap, struct nouveau_pixmap *priv)
{
dixSetPrivate(&pixmap->devPrivates, &glamor_private, priv);
diff --git a/src/nouveau_glamor.h b/src/nouveau_glamor.h
index ef01317..45c1b0a 100644
--- a/src/nouveau_glamor.h
+++ b/src/nouveau_glamor.h
@@ -15,12 +15,15 @@ Bool nouveau_glamor_pre_init(ScrnInfoPtr scrn);
Bool nouveau_glamor_init(ScreenPtr screen);
Bool nouveau_glamor_create_screen_resources(ScreenPtr screen);
XF86VideoAdaptorPtr nouveau_glamor_xv_init(ScreenPtr pScreen, int num_adapt);
+void nouveau_glamor_pixmap_set(PixmapPtr pixmap, struct nouveau_pixmap *priv);
struct nouveau_pixmap *nouveau_glamor_pixmap_get(PixmapPtr pixmap);
#else
static inline Bool nouveau_glamor_pre_init(ScrnInfoPtr scrn) { return FALSE; }
static inline Bool nouveau_glamor_init(ScreenPtr screen) { return FALSE; }
static inline Bool
nouveau_glamor_create_screen_resources(ScreenPtr screen) { return FALSE; }
+static inline void
+nouveau_glamor_pixmap_set(PixmapPtr, struct nouveau_pixmap *) { }
static inline struct nouveau_pixmap *
nouveau_glamor_pixmap_get(PixmapPtr pixmap) { return NULL; }
static inline XF86VideoAdaptorPtr
diff --git a/src/nouveau_present.c b/src/nouveau_present.c
new file mode 100644
index 0000000..b294bbe
--- /dev/null
+++ b/src/nouveau_present.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nouveau_present.h"
+#ifdef DRI3
+#include "nv_include.h"
+#include "nouveau_glamor.h"
+#include "xf86drmMode.h"
+
+struct nouveau_present {
+ struct present_screen_info info;
+};
+
+static RRCrtcPtr
+nouveau_present_crtc(WindowPtr window)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ xf86CrtcPtr crtc;
+ unsigned mask;
+ int head;
+
+ mask = nv_window_belongs_to_crtc(scrn, window->drawable.x,
+ window->drawable.y,
+ window->drawable.width,
+ window->drawable.height);
+
+ head = ffs(mask) - 1;
+ if (head < 0 || head >= xf86_config->num_crtc)
+ return NULL;
+
+ crtc = xf86_config->crtc[head];
+ if (crtc->rotatedData)
+ return NULL;
+
+ return crtc->randr_crtc;
+}
+
+static int
+nouveau_present_ust_msc(RRCrtcPtr rrcrtc, uint64_t *ust, uint64_t *msc)
+{
+ xf86CrtcPtr crtc = rrcrtc->devPrivate;
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+ NVPtr pNv = NVPTR(crtc->scrn);
+ drmVBlank args;
+ int ret, i;
+
+ for (i = 0; i < xf86_config->num_crtc; i++) {
+ if (xf86_config->crtc[i] == crtc)
+ break;
+ }
+
+ if (i == xf86_config->num_crtc)
+ return BadMatch;
+
+ args.request.type = DRM_VBLANK_RELATIVE;
+ args.request.type |= i << DRM_VBLANK_HIGH_CRTC_SHIFT;
+ args.request.sequence = 0,
+ args.request.signal = 0,
+
+ ret = drmWaitVBlank(pNv->dev->fd, &args);
+ if (ret) {
+ *ust = *msc = 0;
+ return BadMatch;
+ }
+
+ *ust = (CARD64)args.reply.tval_sec * 1000000 + args.reply.tval_usec;
+ *msc = args.reply.sequence;
+ return Success;
+}
+
+struct nouveau_present_vblank {
+ uint64_t msc;
+};
+
+static void
+nouveau_present_vblank(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo)
+{
+ struct nouveau_present_vblank *event = priv;
+ uint64_t msc;
+
+ msc = (event->msc & 0xffffffff00000000ULL) | msc_lo;
+ if (msc < event->msc)
+ event->msc += 1ULL << 32;
+
+ present_event_notify(name, ust, msc);
+}
+
+static int
+nouveau_present_vblank_queue(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc)
+{
+ xf86CrtcPtr crtc = rrcrtc->devPrivate;
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+ NVPtr pNv = NVPTR(crtc->scrn);
+ drmVBlank args;
+ struct nouveau_present_vblank *event;
+ void *token;
+ int ret, i;
+
+ for (i = 0; i < xf86_config->num_crtc; i++) {
+ if (xf86_config->crtc[i] == crtc)
+ break;
+ }
+
+ if (i == xf86_config->num_crtc)
+ return BadMatch;
+
+ event = drmmode_event_queue(crtc->scrn, event_id, sizeof(*event),
+ nouveau_present_vblank, &token);
+ if (!event)
+ return BadAlloc;
+
+ event->msc = msc;
+
+ args.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
+ args.request.type |= i << DRM_VBLANK_HIGH_CRTC_SHIFT;
+ args.request.sequence = msc;
+ args.request.signal = (unsigned long)token;
+
+ while ((ret = drmWaitVBlank(pNv->dev->fd, &args)) != 0) {
+ if (errno != EBUSY || drmmode_event_flush(crtc->scrn) < 0)
+ return BadAlloc;
+ }
+
+ return Success;
+}
+
+static void
+nouveau_present_vblank_abort(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc)
+{
+ xf86CrtcPtr crtc = rrcrtc->devPrivate;
+ drmmode_event_abort(crtc->scrn, event_id, true);
+}
+
+static void
+nouveau_present_flush(WindowPtr window)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
+ NVPtr pNv = NVPTR(scrn);
+ if (pNv->Flush)
+ pNv->Flush(scrn);
+}
+
+struct nouveau_present_flip {
+ uint64_t msc;
+ uint32_t old;
+ int fd;
+};
+
+static Bool
+nouveau_present_flip_check(RRCrtcPtr rrcrtc, WindowPtr window,
+ PixmapPtr pixmap, Bool sync_flip)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
+ xf86CrtcPtr crtc = rrcrtc->devPrivate;
+
+ if (!scrn->vtSema || !crtc->enabled)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+nouveau_present_flip(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo)
+{
+ struct nouveau_present_flip *flip = priv;
+ uint64_t msc;
+
+ msc = (flip->msc & ~0xffffffffULL) | msc_lo;
+ if (msc < flip->msc)
+ msc += 1ULL << 32;
+
+ present_event_notify(name, ust, msc);
+ drmModeRmFB(flip->fd, flip->old);
+}
+
+static Bool
+nouveau_present_flip_exec(ScrnInfoPtr scrn, uint64_t event_id, int sync,
+ uint64_t target_msc, PixmapPtr pixmap, Bool vsync)
+{
+ ScreenPtr screen = scrn->pScreen;
+ struct nouveau_pixmap *priv;
+ NVPtr pNv = NVPTR(scrn);
+ uint32_t next_fb;
+ CARD16 stride;
+ CARD32 size;
+ void *token;
+ int ret;
+
+ priv = nouveau_glamor_pixmap_get(pixmap);
+ if (priv == NULL) {
+ int fd = glamor_fd_from_pixmap(screen, pixmap, &stride, &size);
+ if (fd < 0)
+ return FALSE;
+
+ priv = calloc(1, sizeof(*priv));
+ if (!priv)
+ return FALSE;
+
+ ret = nouveau_bo_prime_handle_ref(pNv->dev, fd, &priv->bo);
+ if (ret) {
+ free(priv);
+ return FALSE;
+ }
+
+ nouveau_glamor_pixmap_set(pixmap, priv);
+ }
+
+ ret = drmModeAddFB(pNv->dev->fd, pixmap->drawable.width,
+ pixmap->drawable.height, pixmap->drawable.depth,
+ pixmap->drawable.bitsPerPixel, pixmap->devKind,
+ priv->bo->handle, &next_fb);
+ if (ret == 0) {
+ struct nouveau_present_flip *flip =
+ drmmode_event_queue(scrn, event_id, sizeof(*flip),
+ nouveau_present_flip, &token);
+ if (flip) {
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ int last = 0, i;
+
+ drmmode_swap(scrn, next_fb, &flip->old);
+ flip->fd = pNv->dev->fd;
+ flip->msc = target_msc;
+
+ for (i = 0; i < config->num_crtc; i++) {
+ if (config->crtc[i]->enabled)
+ last = i;
+ }
+
+ for (i = 0; i < config->num_crtc; i++) {
+ int type = vsync ? 0 : DRM_MODE_PAGE_FLIP_ASYNC;
+ int head = drmmode_head(config->crtc[i]);
+ void *user = NULL;
+
+ if (!config->crtc[i]->enabled)
+ continue;
+
+ if (token && ((head == sync) || (i == last))) {
+ type |= DRM_MODE_PAGE_FLIP_EVENT;
+ user = token;
+ }
+
+ ret = drmModePageFlip(pNv->dev->fd, head,
+ next_fb, type, user);
+ if (ret == 0 && user) {
+ token = NULL;
+ }
+ }
+
+ if (token == NULL) {
+ return TRUE;
+ }
+
+ drmmode_swap(scrn, flip->old, &next_fb);
+ drmmode_event_abort(scrn, event_id, false);
+ }
+
+ drmModeRmFB(pNv->dev->fd, next_fb);
+ }
+
+ return FALSE;
+}
+
+static Bool
+nouveau_present_flip_next(RRCrtcPtr rrcrtc, uint64_t event_id,
+ uint64_t target_msc, PixmapPtr pixmap, Bool vsync)
+{
+ xf86CrtcPtr crtc = rrcrtc->devPrivate;
+ ScrnInfoPtr scrn = crtc->scrn;
+ return nouveau_present_flip_exec(scrn, event_id, drmmode_head(crtc),
+ target_msc, pixmap, vsync);
+}
+
+static void
+nouveau_present_flip_stop(ScreenPtr screen, uint64_t event_id)
+{
+ PixmapPtr pixmap = screen->GetScreenPixmap(screen);
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ nouveau_present_flip_exec(scrn, event_id, 0, 0, pixmap, TRUE);
+}
+
+void
+nouveau_present_fini(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ NVPtr pNv = NVPTR(scrn);
+ if (pNv->present) {
+ free(pNv->present);
+ pNv->present = NULL;
+ }
+}
+
+int
+nouveau_present_init(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ NVPtr pNv = NVPTR(scrn);
+ struct nouveau_present *present;
+ uint64_t value;
+ int ret;
+
+ if (pNv->AccelMethod != GLAMOR)
+ return -ENOSYS;
+
+ present = pNv->present = calloc(1, sizeof(*present));
+ if (!present)
+ return -ENOMEM;
+
+ present->info.version = PRESENT_SCREEN_INFO_VERSION;
+ present->info.get_crtc = nouveau_present_crtc;
+ present->info.get_ust_msc = nouveau_present_ust_msc;
+ present->info.queue_vblank = nouveau_present_vblank_queue;
+ present->info.abort_vblank = nouveau_present_vblank_abort;
+ present->info.flush = nouveau_present_flush;
+
+ if (pNv->has_pageflip) {
+#ifdef DRM_CAP_ASYNC_PAGE_FLIP
+ ret = drmGetCap(pNv->dev->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value);
+ if (ret == 0 && value == 1)
+ present->info.capabilities |= PresentCapabilityAsync;
+#endif
+ present->info.check_flip = nouveau_present_flip_check;
+ present->info.flip = nouveau_present_flip_next;
+ present->info.unflip = nouveau_present_flip_stop;
+ }
+
+ return present_screen_init(screen, &present->info);
+}
+#endif
diff --git a/src/nouveau_present.h b/src/nouveau_present.h
new file mode 100644
index 0000000..dea19ce
--- /dev/null
+++ b/src/nouveau_present.h
@@ -0,0 +1,15 @@
+#ifndef __NOUVEAU_PRESENT_H__
+#define __NOUVEAU_PRESENT_H__
+
+#include "xorg-server.h"
+#include "scrnintstr.h"
+
+#ifdef DRI3
+#include "present.h"
+Bool nouveau_present_init(ScreenPtr pScreen);
+void nouveau_present_fini(ScreenPtr pScreen);
+#else
+static inline Bool nouveau_present_init(ScreenPtr pScreen) { return FALSE; }
+static inline void nouveau_present_fini(ScreenPtr pScreen) { }
+#endif
+#endif
diff --git a/src/nv_driver.c b/src/nv_driver.c
index 1174957..db66de6 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -34,6 +34,7 @@
#include "nouveau_copy.h"
#include "nouveau_glamor.h"
+#include "nouveau_present.h"
#include "nouveau_sync.h"
/*
@@ -620,6 +621,7 @@ NVCloseScreen(CLOSE_SCREEN_ARGS_DECL)
if (XF86_CRTC_CONFIG_PTR(pScrn)->num_crtc)
drmmode_screen_fini(pScreen);
+ nouveau_present_fini(pScreen);
nouveau_dri2_fini(pScreen);
nouveau_sync_fini(pScreen);
nouveau_copy_fini(pScreen);
@@ -1325,6 +1327,7 @@ NVScreenInit(SCREEN_INIT_ARGS_DECL)
nouveau_copy_init(pScreen);
nouveau_sync_init(pScreen);
nouveau_dri2_init(pScreen);
+ nouveau_present_init(pScreen);
/* Allocate and map memory areas we need */
if (!NVMapMem(pScrn))
diff --git a/src/nv_type.h b/src/nv_type.h
index 6485ee0..3c52e4e 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -128,6 +128,9 @@ typedef struct _NVRec {
/* SYNC extension private */
void *sync;
+ /* Present extension private */
+ void *present;
+
/* Acceleration context */
PixmapPtr pspix, pmpix, pdpix;
PicturePtr pspict, pmpict;