diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-11-18 14:42:02 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-06-20 14:29:32 +1000 |
commit | 882ebb4000803f6025e1bb3213a31b19f6d1a2c6 (patch) | |
tree | fa0acb993dcee78bb42d000d0acb9c5378ea2e23 | |
parent | 0d94f32fce2759c4b0f4d22b99f3ced09c2aa5a0 (diff) | |
download | xorg-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.am | 4 | ||||
-rw-r--r-- | src/nouveau_glamor.c | 2 | ||||
-rw-r--r-- | src/nouveau_glamor.h | 3 | ||||
-rw-r--r-- | src/nouveau_present.c | 350 | ||||
-rw-r--r-- | src/nouveau_present.h | 15 | ||||
-rw-r--r-- | src/nv_driver.c | 3 | ||||
-rw-r--r-- | src/nv_type.h | 3 |
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; |