diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-11-21 09:34:00 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-11-22 14:45:55 +1000 |
commit | 0c8529ce05e5f6bb812a04754ca139c691dd6305 (patch) | |
tree | 485bef58f4f651e22114f5102793a147e70dcb13 | |
parent | c08c3fd534700ec9aa0f6b8c854d0c932f503dba (diff) | |
download | xorg-driver-xf86-video-nouveau-0c8529ce05e5f6bb812a04754ca139c691dd6305.tar.gz |
dri2: pull in flip handling bits from drmmode_display locally
To avoid busting DRI2 while trying some different things for DRI3.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r-- | src/drmmode_display.c | 135 | ||||
-rw-r--r-- | src/nouveau_dri2.c | 379 | ||||
-rw-r--r-- | src/nv_proto.h | 10 |
3 files changed, 261 insertions, 263 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 3e8ccec..df3e43b 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -85,21 +85,6 @@ typedef struct { drmmode_prop_ptr props; } drmmode_output_private_rec, *drmmode_output_private_ptr; -typedef struct { - drmmode_ptr drmmode; - unsigned old_fb_id; - int flip_count; - void *event_data; - unsigned int fe_frame; - unsigned int fe_tv_sec; - unsigned int fe_tv_usec; -} drmmode_flipdata_rec, *drmmode_flipdata_ptr; - -typedef struct { - drmmode_flipdata_ptr flipdata; - Bool dispatch_me; -} drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr; - static void drmmode_output_dpms(xf86OutputPtr output, int mode); static drmmode_ptr @@ -1377,90 +1362,6 @@ drmmode_cursor_init(ScreenPtr pScreen) return xf86_cursors_init(pScreen, size, size, flags); } -Bool -drmmode_page_flip(DrawablePtr draw, PixmapPtr back, void *priv, - unsigned int ref_crtc_hw_id) -{ - ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private; - drmmode_ptr mode = crtc->drmmode; - int ret, i, old_fb_id; - int emitted = 0; - drmmode_flipdata_ptr flipdata; - drmmode_flipevtcarrier_ptr flipcarrier; - - old_fb_id = mode->fb_id; - ret = drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY, - scrn->depth, scrn->bitsPerPixel, - scrn->displayWidth * scrn->bitsPerPixel / 8, - nouveau_pixmap_bo(back)->handle, &mode->fb_id); - if (ret) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "add fb failed: %s\n", strerror(errno)); - return FALSE; - } - - flipdata = calloc(1, sizeof(drmmode_flipdata_rec)); - if (!flipdata) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "flip queue: data alloc failed.\n"); - goto error_undo; - } - - flipdata->event_data = priv; - flipdata->drmmode = mode; - - for (i = 0; i < config->num_crtc; i++) { - crtc = config->crtc[i]->driver_private; - - if (!config->crtc[i]->enabled) - continue; - - flipdata->flip_count++; - - flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec)); - if (!flipcarrier) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "flip queue: carrier alloc failed.\n"); - if (emitted == 0) - free(flipdata); - goto error_undo; - } - - /* Only the reference crtc will finally deliver its page flip - * completion event. All other crtc's events will be discarded. - */ - flipcarrier->dispatch_me = ((1 << i) == ref_crtc_hw_id); - flipcarrier->flipdata = flipdata; - - ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id, - mode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, - flipcarrier); - if (ret) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "flip queue failed: %s\n", strerror(errno)); - - free(flipcarrier); - if (emitted == 0) - free(flipdata); - goto error_undo; - } - - emitted++; - } - - /* Will release old fb after all crtc's completed flip. */ - flipdata->old_fb_id = old_fb_id; - - return TRUE; - -error_undo: - drmModeRmFB(mode->fd, mode->fb_id); - mode->fb_id = old_fb_id; - return FALSE; -} - #ifdef HAVE_LIBUDEV static void drmmode_handle_uevents(ScrnInfoPtr scrn) @@ -1525,42 +1426,6 @@ drmmode_uevent_fini(ScrnInfoPtr scrn) } static void -drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) -{ - drmmode_flipevtcarrier_ptr flipcarrier = event_data; - drmmode_flipdata_ptr flipdata = flipcarrier->flipdata; - drmmode_ptr drmmode = flipdata->drmmode; - - /* Is this the event whose info shall be delivered to higher level? */ - if (flipcarrier->dispatch_me) { - /* Yes: Cache msc, ust for later delivery. */ - flipdata->fe_frame = frame; - flipdata->fe_tv_sec = tv_sec; - flipdata->fe_tv_usec = tv_usec; - } - free(flipcarrier); - - /* Last crtc completed flip? */ - flipdata->flip_count--; - if (flipdata->flip_count > 0) - return; - - /* Release framebuffer */ - drmModeRmFB(drmmode->fd, flipdata->old_fb_id); - - if (flipdata->event_data == NULL) { - free(flipdata); - return; - } - - /* Deliver cached msc, ust from reference crtc to flip event handler */ - nouveau_dri2_flip_event_handler(flipdata->fe_frame, flipdata->fe_tv_sec, - flipdata->fe_tv_usec, flipdata->event_data); - free(flipdata); -} - -static void drmmode_wakeup_handler(pointer data, int err, pointer p) { ScrnInfoPtr scrn = data; diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c index 3785956..3e6defb 100644 --- a/src/nouveau_dri2.c +++ b/src/nouveau_dri2.c @@ -11,6 +11,8 @@ #error "This driver requires a DRI2-enabled X server" #endif +#include "xf86drmMode.h" + struct nouveau_dri2_buffer { DRI2BufferRec base; PixmapPtr ppix; @@ -295,6 +297,262 @@ can_sync_to_vblank(DrawablePtr draw) draw->width, draw->height); } +#if DRI2INFOREC_VERSION >= 6 +static Bool +nouveau_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); + NVPtr pNv = NVPTR(scrn); + + if ((swap_limit < 1 ) || (swap_limit > pNv->max_swap_limit)) + return FALSE; + + return TRUE; +} +#endif + +/* Shall we intentionally violate the OML_sync_control spec to + * get some sort of triple-buffering behaviour on a pre 1.12.0 + * x-server? + */ +static Bool violate_oml(DrawablePtr draw) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); + NVPtr pNv = NVPTR(scrn); + + return (DRI2INFOREC_VERSION < 6) && (pNv->swap_limit > 1); +} + +typedef struct { + int fd; + unsigned old_fb_id; + int flip_count; + void *event_data; + unsigned int fe_frame; + unsigned int fe_tv_sec; + unsigned int fe_tv_usec; +} drmmode_flipdata_rec, *drmmode_flipdata_ptr; + +typedef struct { + drmmode_flipdata_ptr flipdata; + Bool dispatch_me; +} drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr; + +static void +nouveau_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data) +{ + struct nouveau_dri2_vblank_state *flip = event_data; + DrawablePtr draw; + ScreenPtr screen; + ScrnInfoPtr scrn; + int status; + + status = dixLookupDrawable(&draw, flip->draw, serverClient, + M_ANY, DixWriteAccess); + if (status != Success) { + free(flip); + return; + } + + screen = draw->pScreen; + scrn = xf86ScreenToScrn(screen); + + /* We assume our flips arrive in order, so we don't check the frame */ + switch (flip->action) { + case SWAP: + /* Check for too small vblank count of pageflip completion, + * taking wraparound into account. This usually means some + * defective kms pageflip completion, causing wrong (msc, ust) + * return values and possible visual corruption. + * Skip test for frame == 0, as this is a valid constant value + * reported by all Linux kernels at least up to Linux 3.0. + */ + if ((frame != 0) && + (frame < flip->frame) && (flip->frame - frame < 5)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "%s: Pageflip has impossible msc %d < target_msc %d\n", + __func__, frame, flip->frame); + /* All-Zero values signal failure of (msc, ust) + * timestamping to client. + */ + frame = tv_sec = tv_usec = 0; + } + + DRI2SwapComplete(flip->client, draw, frame, tv_sec, tv_usec, + DRI2_FLIP_COMPLETE, flip->func, + flip->data); + break; + default: + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "%s: unknown vblank event received\n", __func__); + /* Unknown type */ + break; + } + + free(flip); +} + +void +drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data) +{ + drmmode_flipevtcarrier_ptr flipcarrier = event_data; + drmmode_flipdata_ptr flipdata = flipcarrier->flipdata; + + /* Is this the event whose info shall be delivered to higher level? */ + if (flipcarrier->dispatch_me) { + /* Yes: Cache msc, ust for later delivery. */ + flipdata->fe_frame = frame; + flipdata->fe_tv_sec = tv_sec; + flipdata->fe_tv_usec = tv_usec; + } + free(flipcarrier); + + /* Last crtc completed flip? */ + flipdata->flip_count--; + if (flipdata->flip_count > 0) + return; + + /* Release framebuffer */ + drmModeRmFB(flipdata->fd, flipdata->old_fb_id); + + if (flipdata->event_data == NULL) { + free(flipdata); + return; + } + + /* Deliver cached msc, ust from reference crtc to flip event handler */ + nouveau_dri2_flip_event_handler(flipdata->fe_frame, flipdata->fe_tv_sec, + flipdata->fe_tv_usec, flipdata->event_data); + free(flipdata); +} + +static Bool +drmmode_page_flip(DrawablePtr draw, PixmapPtr back, void *priv, + unsigned int ref_crtc_hw_id) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + NVPtr pNv = NVPTR(scrn); + uint32_t next_fb; + int emitted = 0; + int ret, i; + drmmode_flipdata_ptr flipdata; + drmmode_flipevtcarrier_ptr flipcarrier; + + ret = drmModeAddFB(pNv->dev->fd, scrn->virtualX, scrn->virtualY, + scrn->depth, scrn->bitsPerPixel, + scrn->displayWidth * scrn->bitsPerPixel / 8, + nouveau_pixmap_bo(back)->handle, &next_fb); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "add fb failed: %s\n", strerror(errno)); + return FALSE; + } + + flipdata = calloc(1, sizeof(drmmode_flipdata_rec)); + if (!flipdata) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue: data alloc failed.\n"); + goto error_undo; + } + + flipdata->event_data = priv; + flipdata->fd = pNv->dev->fd; + + for (i = 0; i < config->num_crtc; i++) { + int head = drmmode_head(config->crtc[i]); + + if (!config->crtc[i]->enabled) + continue; + + flipdata->flip_count++; + + flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec)); + if (!flipcarrier) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue: carrier alloc failed.\n"); + if (emitted == 0) + free(flipdata); + goto error_undo; + } + + /* Only the reference crtc will finally deliver its page flip + * completion event. All other crtc's events will be discarded. + */ + flipcarrier->dispatch_me = ((1 << i) == ref_crtc_hw_id); + flipcarrier->flipdata = flipdata; + + ret = drmModePageFlip(pNv->dev->fd, head, next_fb, + DRM_MODE_PAGE_FLIP_EVENT, flipcarrier); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue failed: %s\n", strerror(errno)); + + free(flipcarrier); + if (emitted == 0) + free(flipdata); + goto error_undo; + } + + emitted++; + } + + /* Will release old fb after all crtc's completed flip. */ + drmmode_swap(scrn, next_fb, &flipdata->old_fb_id); + return TRUE; + +error_undo: + drmModeRmFB(pNv->dev->fd, next_fb); + return FALSE; +} + +static void +nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame, + unsigned int tv_sec, unsigned int tv_usec, + struct nouveau_dri2_vblank_state *s); + +void +nouveau_dri2_vblank_handler(int fd, unsigned int frame, + unsigned int tv_sec, unsigned int tv_usec, + void *event_data) +{ + struct nouveau_dri2_vblank_state *s = event_data; + DrawablePtr draw; + int ret; + + ret = dixLookupDrawable(&draw, s->draw, serverClient, + M_ANY, DixWriteAccess); + if (ret) { + free(s); + return; + } + + switch (s->action) { + case SWAP: + nouveau_dri2_finish_swap(draw, frame, tv_sec, tv_usec, s); +#if DRI2INFOREC_VERSION >= 6 + /* Restore real swap limit on drawable, now that it is safe. */ + ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); + DRI2SwapLimit(draw, NVPTR(scrn)->swap_limit); +#endif + + break; + + case WAIT: + DRI2WaitMSCComplete(s->client, draw, frame, tv_sec, tv_usec); + free(s); + break; + + case BLIT: + DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec, + DRI2_BLIT_COMPLETE, s->func, s->data); + free(s); + break; + } +} + static int nouveau_wait_vblank(DrawablePtr draw, int type, CARD64 msc, CARD64 *pmsc, CARD64 *pust, void *data) @@ -325,32 +583,6 @@ nouveau_wait_vblank(DrawablePtr draw, int type, CARD64 msc, return 0; } -#if DRI2INFOREC_VERSION >= 6 -static Bool -nouveau_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit) -{ - ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); - NVPtr pNv = NVPTR(scrn); - - if ((swap_limit < 1 ) || (swap_limit > pNv->max_swap_limit)) - return FALSE; - - return TRUE; -} -#endif - -/* Shall we intentionally violate the OML_sync_control spec to - * get some sort of triple-buffering behaviour on a pre 1.12.0 - * x-server? - */ -static Bool violate_oml(DrawablePtr draw) -{ - ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); - NVPtr pNv = NVPTR(scrn); - - return (DRI2INFOREC_VERSION < 6) && (pNv->swap_limit > 1); -} - static void nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, @@ -671,101 +903,6 @@ nouveau_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) return TRUE; } -void -nouveau_dri2_vblank_handler(int fd, unsigned int frame, - unsigned int tv_sec, unsigned int tv_usec, - void *event_data) -{ - struct nouveau_dri2_vblank_state *s = event_data; - DrawablePtr draw; - int ret; - - ret = dixLookupDrawable(&draw, s->draw, serverClient, - M_ANY, DixWriteAccess); - if (ret) { - free(s); - return; - } - - switch (s->action) { - case SWAP: - nouveau_dri2_finish_swap(draw, frame, tv_sec, tv_usec, s); -#if DRI2INFOREC_VERSION >= 6 - /* Restore real swap limit on drawable, now that it is safe. */ - ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); - DRI2SwapLimit(draw, NVPTR(scrn)->swap_limit); -#endif - - break; - - case WAIT: - DRI2WaitMSCComplete(s->client, draw, frame, tv_sec, tv_usec); - free(s); - break; - - case BLIT: - DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec, - DRI2_BLIT_COMPLETE, s->func, s->data); - free(s); - break; - } -} - -void -nouveau_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) -{ - struct nouveau_dri2_vblank_state *flip = event_data; - DrawablePtr draw; - ScreenPtr screen; - ScrnInfoPtr scrn; - int status; - - status = dixLookupDrawable(&draw, flip->draw, serverClient, - M_ANY, DixWriteAccess); - if (status != Success) { - free(flip); - return; - } - - screen = draw->pScreen; - scrn = xf86ScreenToScrn(screen); - - /* We assume our flips arrive in order, so we don't check the frame */ - switch (flip->action) { - case SWAP: - /* Check for too small vblank count of pageflip completion, - * taking wraparound into account. This usually means some - * defective kms pageflip completion, causing wrong (msc, ust) - * return values and possible visual corruption. - * Skip test for frame == 0, as this is a valid constant value - * reported by all Linux kernels at least up to Linux 3.0. - */ - if ((frame != 0) && - (frame < flip->frame) && (flip->frame - frame < 5)) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "%s: Pageflip has impossible msc %d < target_msc %d\n", - __func__, frame, flip->frame); - /* All-Zero values signal failure of (msc, ust) - * timestamping to client. - */ - frame = tv_sec = tv_usec = 0; - } - - DRI2SwapComplete(flip->client, draw, frame, tv_sec, tv_usec, - DRI2_FLIP_COMPLETE, flip->func, - flip->data); - break; - default: - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "%s: unknown vblank event received\n", __func__); - /* Unknown type */ - break; - } - - free(flip); -} - Bool nouveau_dri2_init(ScreenPtr pScreen) { diff --git a/src/nv_proto.h b/src/nv_proto.h index f45c0d6..09f7ede 100644 --- a/src/nv_proto.h +++ b/src/nv_proto.h @@ -7,14 +7,15 @@ void drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y); void drmmode_remove_fb(ScrnInfoPtr pScrn); Bool drmmode_cursor_init(ScreenPtr pScreen); void drmmode_fbcon_copy(ScreenPtr pScreen); -Bool drmmode_page_flip(DrawablePtr draw, PixmapPtr back, void *priv, - unsigned int ref_crtc_hw_id); void drmmode_screen_init(ScreenPtr pScreen); void drmmode_screen_fini(ScreenPtr pScreen); int drmmode_head(xf86CrtcPtr crtc); void drmmode_swap(ScrnInfoPtr, uint32_t, uint32_t *); +void drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, void *event_data); +void nouveau_dri2_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, void *event_data); + /* in nv_accel_common.c */ Bool NVAccelCommonInit(ScrnInfoPtr pScrn); Bool NVAccelGetCtxSurf2DFormatFromPixmap(PixmapPtr pPix, int *fmt_ret); @@ -27,11 +28,6 @@ Bool nouveau_allocate_surface(ScrnInfoPtr scrn, int width, int height, struct nouveau_bo **bo); /* in nouveau_dri2.c */ -void nouveau_dri2_vblank_handler(int fd, unsigned int frame, - unsigned int tv_sec, unsigned int tv_usec, - void *event_data); -void nouveau_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data); Bool nouveau_dri2_init(ScreenPtr pScreen); void nouveau_dri2_fini(ScreenPtr pScreen); |