From 8218dadd30eb0c87efbac6db5d8e3862a236b6a4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 9 Jun 2015 15:30:22 +1000 Subject: [PATCH 01/14] cursor: drop ARGB_CURSOR I doubt anyone builds with this turned off or has done for a long time. It helps my eyes bleed slightly less when reading the code, I've left the define in place as some drivers use it. Reviewed-by: Aaron Plattner Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- dix/cursor.c | 8 -------- hw/kdrive/ephyr/ephyrcursor.c | 4 ---- hw/xfree86/modes/xf86Cursors.c | 8 -------- hw/xfree86/ramdac/xf86Cursor.c | 2 -- hw/xfree86/ramdac/xf86Cursor.h | 4 ---- hw/xfree86/ramdac/xf86HWCurs.c | 6 ------ hw/xquartz/xpr/xprCursor.c | 2 -- include/cursorstr.h | 2 -- mi/midispcur.c | 20 +------------------- xfixes/cursor.c | 2 -- 10 files changed, 1 insertion(+), 57 deletions(-) diff --git a/dix/cursor.c b/dix/cursor.c index 1525857e3..e45945619 100644 --- a/dix/cursor.c +++ b/dix/cursor.c @@ -80,9 +80,7 @@ FreeCursorBits(CursorBitsPtr bits) return; free(bits->source); free(bits->mask); -#ifdef ARGB_CURSOR free(bits->argb); -#endif dixFiniPrivates(bits, PRIVATE_CURSOR_BITS); if (bits->refcnt == 0) { GlyphSharePtr *prev, this; @@ -165,7 +163,6 @@ CheckForEmptyMask(CursorBitsPtr bits) while (n--) if (*(msk++) != 0) return; -#ifdef ARGB_CURSOR if (bits->argb) { CARD32 *argb = bits->argb; @@ -174,7 +171,6 @@ CheckForEmptyMask(CursorBitsPtr bits) if (*argb++ & 0xff000000) return; } -#endif bits->emptyMask = TRUE; } @@ -259,9 +255,7 @@ AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits, dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS) bits->source = psrcbits; bits->mask = pmaskbits; -#ifdef ARGB_CURSOR bits->argb = argb; -#endif bits->width = cm->width; bits->height = cm->height; bits->xhot = cm->xhot; @@ -400,9 +394,7 @@ AllocGlyphCursor(Font source, unsigned sourceChar, Font mask, unsigned maskChar, dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS); bits->source = srcbits; bits->mask = mskbits; -#ifdef ARGB_CURSOR bits->argb = 0; -#endif bits->width = cm.width; bits->height = cm.height; bits->xhot = cm.xhot; diff --git a/hw/kdrive/ephyr/ephyrcursor.c b/hw/kdrive/ephyr/ephyrcursor.c index 852be33e0..808b3c72c 100644 --- a/hw/kdrive/ephyr/ephyrcursor.c +++ b/hw/kdrive/ephyr/ephyrcursor.c @@ -100,7 +100,6 @@ ephyrRealizeCoreCursor(EphyrScrPriv *scr, CursorPtr cursor) xcb_free_pixmap(conn, mask); } -#ifdef ARGB_CURSOR static xcb_render_pictformat_t get_argb_format(void) { @@ -170,7 +169,6 @@ can_argb_cursor(void) return v->major_version == 0 && v->minor_version >= 5; } -#endif static Bool ephyrRealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor) @@ -179,11 +177,9 @@ ephyrRealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor) KdScreenInfo *kscr = pScreenPriv->screen; EphyrScrPriv *scr = kscr->driver; -#ifdef ARGB_CURSOR if (cursor->bits->argb && can_argb_cursor()) ephyrRealizeARGBCursor(scr, cursor); else -#endif { ephyrRealizeCoreCursor(scr, cursor); } diff --git a/hw/xfree86/modes/xf86Cursors.c b/hw/xfree86/modes/xf86Cursors.c index 379a27a76..321cde775 100644 --- a/hw/xfree86/modes/xf86Cursors.c +++ b/hw/xfree86/modes/xf86Cursors.c @@ -258,9 +258,7 @@ xf86_crtc_convert_cursor_to_argb(xf86CrtcPtr crtc, unsigned char *src) CARD32 bits; const Rotation rotation = xf86_crtc_cursor_rotation(crtc); -#ifdef ARGB_CURSOR crtc->cursor_argb = FALSE; -#endif for (y = 0; y < cursor_info->MaxHeight; y++) for (x = 0; x < cursor_info->MaxWidth; x++) { @@ -458,9 +456,7 @@ xf86_crtc_load_cursor_image(xf86CrtcPtr crtc, CARD8 *src) CARD8 *cursor_image; const Rotation rotation = xf86_crtc_cursor_rotation(crtc); -#ifdef ARGB_CURSOR crtc->cursor_argb = FALSE; -#endif if (rotation == RR_Rotate_0) cursor_image = src; @@ -632,12 +628,10 @@ xf86_cursors_init(ScreenPtr screen, int max_width, int max_height, int flags) cursor_info->HideCursor = xf86_hide_cursors; cursor_info->ShowCursor = xf86_show_cursors; cursor_info->UseHWCursor = xf86_use_hw_cursor; -#ifdef ARGB_CURSOR if (flags & HARDWARE_CURSOR_ARGB) { cursor_info->UseHWCursorARGB = xf86_use_hw_cursor_argb; cursor_info->LoadCursorARGBCheck = xf86_load_cursor_argb; } -#endif xf86_config->cursor = NULL; xf86_hide_cursors(scrn); @@ -691,11 +685,9 @@ xf86_reload_cursors(ScreenPtr screen) void *src = dixLookupScreenPrivate(&cursor->devPrivates, CursorScreenKey, screen); -#ifdef ARGB_CURSOR if (cursor->bits->argb && xf86DriverHasLoadCursorARGB(cursor_info)) xf86DriverLoadCursorARGB(cursor_info, cursor); else if (src) -#endif xf86DriverLoadCursorImage(cursor_info, src); x += scrn->frameX0 + cursor_screen_priv->HotX; diff --git a/hw/xfree86/ramdac/xf86Cursor.c b/hw/xfree86/ramdac/xf86Cursor.c index 04496d531..2a54571cb 100644 --- a/hw/xfree86/ramdac/xf86Cursor.c +++ b/hw/xfree86/ramdac/xf86Cursor.c @@ -340,12 +340,10 @@ xf86CursorSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs, if (infoPtr->pScrn->vtSema && xorg_list_is_empty(&pScreen->pixmap_dirty_list) && (ScreenPriv->ForceHWCursorCount || (( -#ifdef ARGB_CURSOR cursor->bits->argb && infoPtr->UseHWCursorARGB && (*infoPtr->UseHWCursorARGB)(pScreen, cursor)) || (cursor->bits->argb == 0 && -#endif (cursor->bits->height <= infoPtr->MaxHeight) && (cursor->bits->width <= infoPtr->MaxWidth) && (!infoPtr->UseHWCursor || (*infoPtr->UseHWCursor) (pScreen, cursor)))))) { diff --git a/hw/xfree86/ramdac/xf86Cursor.h b/hw/xfree86/ramdac/xf86Cursor.h index a389a9988..8c98bb151 100644 --- a/hw/xfree86/ramdac/xf86Cursor.h +++ b/hw/xfree86/ramdac/xf86Cursor.h @@ -19,11 +19,9 @@ typedef struct _xf86CursorInfoRec { unsigned char *(*RealizeCursor) (struct _xf86CursorInfoRec *, CursorPtr); Bool (*UseHWCursor) (ScreenPtr, CursorPtr); -#ifdef ARGB_CURSOR Bool (*UseHWCursorARGB) (ScreenPtr, CursorPtr); void (*LoadCursorARGB) (ScrnInfoPtr, CursorPtr); Bool (*LoadCursorARGBCheck) (ScrnInfoPtr, CursorPtr); -#endif } xf86CursorInfoRec, *xf86CursorInfoPtr; @@ -77,8 +75,6 @@ extern _X_EXPORT void xf86ForceHWCursor(ScreenPtr pScreen, Bool on); #define HARDWARE_CURSOR_NIBBLE_SWAPPED 0x00000800 #define HARDWARE_CURSOR_SHOW_TRANSPARENT 0x00001000 #define HARDWARE_CURSOR_UPDATE_UNHIDDEN 0x00002000 -#ifdef ARGB_CURSOR #define HARDWARE_CURSOR_ARGB 0x00004000 -#endif #endif /* _XF86CURSOR_H */ diff --git a/hw/xfree86/ramdac/xf86HWCurs.c b/hw/xfree86/ramdac/xf86HWCurs.c index be7154e0f..84febe0df 100644 --- a/hw/xfree86/ramdac/xf86HWCurs.c +++ b/hw/xfree86/ramdac/xf86HWCurs.c @@ -139,9 +139,7 @@ xf86SetCursor(ScreenPtr pScreen, CursorPtr pCurs, int x, int y) x -= infoPtr->pScrn->frameX0 + ScreenPriv->HotX; y -= infoPtr->pScrn->frameY0 + ScreenPriv->HotY; -#ifdef ARGB_CURSOR if (!pCurs->bits->argb || !xf86DriverHasLoadCursorARGB(infoPtr)) -#endif if (!bits) { bits = (*infoPtr->RealizeCursor) (infoPtr, pCurs); dixSetScreenPrivate(&pCurs->devPrivates, CursorScreenKey, pScreen, @@ -151,12 +149,10 @@ xf86SetCursor(ScreenPtr pScreen, CursorPtr pCurs, int x, int y) if (!(infoPtr->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN)) (*infoPtr->HideCursor) (infoPtr->pScrn); -#ifdef ARGB_CURSOR if (pCurs->bits->argb && xf86DriverHasLoadCursorARGB(infoPtr)) { if (!xf86DriverLoadCursorARGB (infoPtr, pCurs)) return FALSE; } else -#endif if (bits) if (!xf86DriverLoadCursorImage (infoPtr, bits)) return FALSE; @@ -213,12 +209,10 @@ xf86RecolorCursor(ScreenPtr pScreen, CursorPtr pCurs, Bool displayed) xf86CursorScreenKey); xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; -#ifdef ARGB_CURSOR /* recoloring isn't applicable to ARGB cursors and drivers shouldn't have to ignore SetCursorColors requests */ if (pCurs->bits->argb) return; -#endif if (ScreenPriv->PalettedCursor) { xColorItem sourceColor, maskColor; diff --git a/hw/xquartz/xpr/xprCursor.c b/hw/xquartz/xpr/xprCursor.c index 4168f7c53..5e89348c0 100644 --- a/hw/xquartz/xpr/xprCursor.c +++ b/hw/xquartz/xpr/xprCursor.c @@ -85,7 +85,6 @@ load_cursor(CursorPtr src, int screen) hot_x = src->bits->xhot; hot_y = src->bits->yhot; -#ifdef ARGB_CURSOR if (src->bits->argb != NULL) { #if BITMAP_BIT_ORDER == MSBFirst rowbytes = src->bits->width * sizeof(CARD32); @@ -104,7 +103,6 @@ load_cursor(CursorPtr src, int screen) #endif } else -#endif { fg_color = 0xFF00 | (src->foreRed >> 8); fg_color <<= 16; diff --git a/include/cursorstr.h b/include/cursorstr.h index 221cd7034..3f306a496 100644 --- a/include/cursorstr.h +++ b/include/cursorstr.h @@ -64,9 +64,7 @@ typedef struct _CursorBits { unsigned short width, height, xhot, yhot; /* metrics */ int refcnt; /* can be shared */ PrivateRec *devPrivates; /* set by pScr->RealizeCursor */ -#ifdef ARGB_CURSOR CARD32 *argb; /* full-color alpha blended */ -#endif } CursorBits, *CursorBitsPtr; #define CURSOR_BITS_SIZE (sizeof(CursorBits) + dixPrivatesSize(PRIVATE_CURSOR_BITS)) diff --git a/mi/midispcur.c b/mi/midispcur.c index 50f0dd212..d1da0fd58 100644 --- a/mi/midispcur.c +++ b/mi/midispcur.c @@ -46,9 +46,7 @@ in this Software without prior written authorization from The Open Group. #include "misprite.h" #include "gcstruct.h" -#ifdef ARGB_CURSOR #include "picturestr.h" -#endif #include "inputstr.h" @@ -68,9 +66,7 @@ typedef struct { GCPtr pSourceGC, pMaskGC; GCPtr pSaveGC, pRestoreGC; PixmapPtr pSave; -#ifdef ARGB_CURSOR PicturePtr pRootPicture; -#endif } miDCBufferRec, *miDCBufferPtr; #define miGetDCDevice(dev, screen) \ @@ -86,9 +82,7 @@ typedef struct { CloseScreenProcPtr CloseScreen; PixmapPtr sourceBits; /* source bits */ PixmapPtr maskBits; /* mask bits */ -#ifdef ARGB_CURSOR PicturePtr pPicture; -#endif CursorPtr pCursor; } miDCScreenRec, *miDCScreenPtr; @@ -133,11 +127,9 @@ miDCSwitchScreenCursor(ScreenPtr pScreen, CursorPtr pCursor, PixmapPtr sourceBit (*pScreen->DestroyPixmap)(pScreenPriv->maskBits); pScreenPriv->maskBits = maskBits; -#ifdef ARGB_CURSOR if (pScreenPriv->pPicture) FreePicture(pScreenPriv->pPicture, 0); pScreenPriv->pPicture = pPicture; -#endif pScreenPriv->pCursor = pCursor; } @@ -162,7 +154,6 @@ miDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) return TRUE; } -#ifdef ARGB_CURSOR #define EnsurePicture(picture,draw,win) (picture || miDCMakePicture(&picture,draw,win)) static PicturePtr @@ -182,7 +173,6 @@ miDCMakePicture(PicturePtr * ppPicture, DrawablePtr pDraw, WindowPtr pWin) *ppPicture = pPicture; return pPicture; } -#endif static Bool miDCRealize(ScreenPtr pScreen, CursorPtr pCursor) @@ -195,8 +185,6 @@ miDCRealize(ScreenPtr pScreen, CursorPtr pCursor) if (pScreenPriv->pCursor == pCursor) return TRUE; -#ifdef ARGB_CURSOR - if (pCursor->bits->argb) { PixmapPtr pPixmap; PictFormatPtr pFormat; @@ -233,7 +221,7 @@ miDCRealize(ScreenPtr pScreen, CursorPtr pCursor) miDCSwitchScreenCursor(pScreen, pCursor, NULL, NULL, pPicture); return TRUE; } -#endif + sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); if (!sourceBits) @@ -373,7 +361,6 @@ miDCPutUpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, pWin = pScreen->root; pBuffer = miGetDCDevice(pDev, pScreen); -#ifdef ARGB_CURSOR if (pScreenPriv->pPicture) { if (!EnsurePicture(pBuffer->pRootPicture, &pWin->drawable, pWin)) return FALSE; @@ -385,7 +372,6 @@ miDCPutUpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, x, y, pCursor->bits->width, pCursor->bits->height); } else -#endif { miDCPutBits((DrawablePtr) pWin, pBuffer->pSourceGC, pBuffer->pMaskGC, @@ -486,9 +472,7 @@ miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) if (!pBuffer->pRestoreGC) goto failure; -#ifdef ARGB_CURSOR pBuffer->pRootPicture = NULL; -#endif /* (re)allocated lazily depending on the cursor size */ pBuffer->pSave = NULL; @@ -525,11 +509,9 @@ miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) if (pBuffer->pRestoreGC) FreeGC(pBuffer->pRestoreGC, (GContext) 0); -#ifdef ARGB_CURSOR /* If a pRootPicture was allocated for a root window, it * is freed when that root window is destroyed, so don't * free it again here. */ -#endif if (pBuffer->pSave) (*pScreen->DestroyPixmap) (pBuffer->pSave); diff --git a/xfixes/cursor.c b/xfixes/cursor.c index 94d24a8e2..5619aad2e 100644 --- a/xfixes/cursor.c +++ b/xfixes/cursor.c @@ -306,11 +306,9 @@ CopyCursorToImage(CursorPtr pCursor, CARD32 *image) int height = pCursor->bits->height; int npixels = width * height; -#ifdef ARGB_CURSOR if (pCursor->bits->argb) memcpy(image, pCursor->bits->argb, npixels * sizeof(CARD32)); else -#endif { unsigned char *srcLine = pCursor->bits->source; unsigned char *mskLine = pCursor->bits->mask; From 5064ee276fe0f6cebc33ea08e57f1de91f092d88 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 12 Jun 2015 15:13:47 +1000 Subject: [PATCH 02/14] xf86Rotate: remove unused macros. These macros aren't used anywhere. v1.1: drop comment (Aaron) Signed-off-by: Dave Airlie --- hw/xfree86/modes/xf86Rotate.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/xfree86/modes/xf86Rotate.c b/hw/xfree86/modes/xf86Rotate.c index 9c00a443f..bc1ea2166 100644 --- a/hw/xfree86/modes/xf86Rotate.c +++ b/hw/xfree86/modes/xf86Rotate.c @@ -43,12 +43,6 @@ #include "X11/extensions/dpmsconst.h" #include "X11/Xatom.h" -/* borrowed from composite extension, move to Render and publish? */ - -#define F(x) IntToxFixed(x) - -#define toF(x) ((float) (x) / 65536.0f) - static void xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, RegionPtr region) { From 5c555605386c76be2f02193d434a4617218b67be Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 11 Jun 2015 14:29:48 +1000 Subject: [PATCH 03/14] xf86: restrict when we auto add devices as gpu devices. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Michel pointed out I broke Zaphod with the initial auto add gpu devices change, Fix this, by only auto adding GPU devices if we are screen 0 and there are no other screens in the layout. Anyone who wants to assign GPU devices can specify it in the xorg.conf for this use case. Signed-off-by: Dave Airlie Tested-by: Michel Dänzer --- hw/xfree86/common/xf86Config.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c index b8ec8a0ef..2b4df0cf7 100644 --- a/hw/xfree86/common/xf86Config.c +++ b/hw/xfree86/common/xf86Config.c @@ -123,7 +123,7 @@ static ModuleDefault ModuleDefaults[] = { /* Forward declarations */ static Bool configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, - int scrnum, MessageType from); + int scrnum, MessageType from, Bool auto_gpu_device); static Bool configMonitor(MonPtr monitorp, XF86ConfMonitorPtr conf_monitor); static Bool configDevice(GDevPtr devicep, XF86ConfDevicePtr conf_device, Bool active, Bool gpu); @@ -1524,7 +1524,7 @@ configLayout(serverLayoutPtr servlayoutp, XF86ConfLayoutPtr conf_layout, else scrnum = adjp->adj_scrnum; if (!configScreen(slp[count].screen, adjp->adj_screen, scrnum, - X_CONFIG)) { + X_CONFIG, (scrnum == 0 && !adjp->list.next))) { do { free(slp[count].screen); } while (count--); @@ -1574,7 +1574,7 @@ configLayout(serverLayoutPtr servlayoutp, XF86ConfLayoutPtr conf_layout, FIND_SUITABLE (XF86ConfScreenPtr, xf86configptr->conf_screen_lst, screen); slp[0].screen = xnfcalloc(1, sizeof(confScreenRec)); if (!configScreen(slp[0].screen, screen, - 0, X_CONFIG)) { + 0, X_CONFIG, TRUE)) { free(slp[0].screen); free(slp); return FALSE; @@ -1703,7 +1703,7 @@ configImpliedLayout(serverLayoutPtr servlayoutp, XF86ConfScreenPtr conf_screen, slp = xnfcalloc(1, 2 * sizeof(screenLayoutRec)); slp[0].screen = xnfcalloc(1, sizeof(confScreenRec)); slp[1].screen = NULL; - if (!configScreen(slp[0].screen, conf_screen, 0, from)) { + if (!configScreen(slp[0].screen, conf_screen, 0, from, TRUE)) { free(slp); return FALSE; } @@ -1768,7 +1768,7 @@ configXvAdaptor(confXvAdaptorPtr adaptor, XF86ConfVideoAdaptorPtr conf_adaptor) static Bool configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, int scrnum, - MessageType from) + MessageType from, Bool auto_gpu_device) { int count = 0; XF86ConfDisplayPtr dispptr; @@ -1825,7 +1825,8 @@ configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, int scrnum, screenp->device = NULL; } - if (conf_screen->num_gpu_devices == 0 && xf86configptr->conf_device_lst) { + if (auto_gpu_device && conf_screen->num_gpu_devices == 0 && + xf86configptr->conf_device_lst) { XF86ConfDevicePtr sdevice = xf86configptr->conf_device_lst->list.next; for (i = 0; i < MAX_GPUDEVICES; i++) { From ea0e4d752b778c1f2132f8d29542f7dabc296415 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 10 Jun 2015 14:46:22 +1000 Subject: [PATCH 04/14] glamor: add support for allocating linear buffers (v2) We need this for doing USB offload scenarios using glamor and modesetting driver. unfortunately only gbm in mesa 10.6 has support for the linear API. v1.1: fix bad define v2: update the configure.ac test as per amdgpu. (Michel) set linear bos to external to avoid cache. (Eric) Reviewed-by: Eric Anholt Signed-off-by: Dave Airlie --- configure.ac | 4 ++++ glamor/glamor.h | 3 ++- glamor/glamor_egl.c | 5 ++++- glamor/glamor_egl_stubs.c | 2 +- glamor/glamor_fbo.c | 13 ++++++++----- hw/xwayland/xwayland-glamor.c | 2 +- include/dix-config.h.in | 3 +++ 7 files changed, 23 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index f760730c3..592e13354 100644 --- a/configure.ac +++ b/configure.ac @@ -2105,6 +2105,10 @@ if test "x$GLAMOR" = xyes; then if test "x$GBM" = xyes; then AC_DEFINE(GLAMOR_HAS_GBM, 1, [Build glamor with GBM-based EGL support]) + AC_CHECK_DECL(GBM_BO_USE_LINEAR, + [AC_DEFINE(GLAMOR_HAS_GBM_LINEAR, 1, [Have GBM_BO_USE_LINEAR])], [], + [#include + #include ]) fi fi diff --git a/glamor/glamor.h b/glamor/glamor.h index 0d57fff88..657354d77 100644 --- a/glamor/glamor.h +++ b/glamor/glamor.h @@ -142,7 +142,8 @@ extern _X_EXPORT void glamor_enable_dri3(ScreenPtr screen); extern _X_EXPORT unsigned int glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, - int h); + int h, + Bool linear); extern _X_EXPORT int glamor_egl_dri3_fd_name_from_tex(ScreenPtr, PixmapPtr, unsigned int, Bool, CARD16 *, CARD32 *); diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c index dc5456118..4c0db6a47 100644 --- a/glamor/glamor_egl.c +++ b/glamor/glamor_egl.c @@ -187,7 +187,7 @@ glamor_egl_get_gbm_device(ScreenPtr screen) } unsigned int -glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h) +glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h, Bool linear) { ScrnInfoPtr scrn = xf86ScreenToScrn(screen); struct glamor_egl_screen_private *glamor_egl; @@ -200,6 +200,9 @@ glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h) glamor_egl = glamor_egl_get_screen_private(scrn); bo = gbm_bo_create(glamor_egl->gbm, w, h, GBM_FORMAT_ARGB8888, +#ifdef GLAMOR_HAS_GBM_LINEAR + (linear ? GBM_BO_USE_LINEAR : 0) | +#endif GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT); if (!bo) return 0; diff --git a/glamor/glamor_egl_stubs.c b/glamor/glamor_egl_stubs.c index a93f62dcb..c11e6d51b 100644 --- a/glamor/glamor_egl_stubs.c +++ b/glamor/glamor_egl_stubs.c @@ -50,7 +50,7 @@ glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, } unsigned int -glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h) +glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h, Bool linear) { return 0; } diff --git a/glamor/glamor_fbo.c b/glamor/glamor_fbo.c index ea0e80102..6017f5e32 100644 --- a/glamor/glamor_fbo.c +++ b/glamor/glamor_fbo.c @@ -228,6 +228,9 @@ glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv, fbo->external = FALSE; fbo->format = format; + if (flag == CREATE_PIXMAP_USAGE_SHARED) + fbo->external = TRUE; + if (flag != GLAMOR_CREATE_FBO_NO_FBO) { if (glamor_pixmap_ensure_fb(glamor_priv, fbo) != 0) { glamor_purge_fbo(glamor_priv, fbo); @@ -313,7 +316,7 @@ glamor_destroy_fbo(glamor_screen_private *glamor_priv, static int _glamor_create_tex(glamor_screen_private *glamor_priv, - int w, int h, GLenum format) + int w, int h, GLenum format, Bool linear) { unsigned int tex = 0; @@ -323,7 +326,7 @@ _glamor_create_tex(glamor_screen_private *glamor_priv, * an ARGB8888 based texture for us. */ if (glamor_priv->dri3_enabled && format == GL_RGBA) { tex = glamor_egl_create_argb8888_based_texture(glamor_priv->screen, - w, h); + w, h, linear); } if (!tex) { glamor_make_current(glamor_priv); @@ -344,14 +347,14 @@ glamor_create_fbo(glamor_screen_private *glamor_priv, glamor_pixmap_fbo *fbo; GLint tex = 0; - if (flag == GLAMOR_CREATE_FBO_NO_FBO) + if (flag == GLAMOR_CREATE_FBO_NO_FBO || flag == CREATE_PIXMAP_USAGE_SHARED) goto new_fbo; fbo = glamor_pixmap_fbo_cache_get(glamor_priv, w, h, format); if (fbo) return fbo; new_fbo: - tex = _glamor_create_tex(glamor_priv, w, h, format); + tex = _glamor_create_tex(glamor_priv, w, h, format, flag == CREATE_PIXMAP_USAGE_SHARED); fbo = glamor_create_fbo_from_tex(glamor_priv, w, h, format, tex, flag); return fbo; @@ -531,7 +534,7 @@ glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag) if (!pixmap_priv->fbo->tex) pixmap_priv->fbo->tex = _glamor_create_tex(glamor_priv, pixmap->drawable.width, - pixmap->drawable.height, format); + pixmap->drawable.height, format, FALSE); if (flag != GLAMOR_CREATE_FBO_NO_FBO && pixmap_priv->fbo->fb == 0) if (glamor_pixmap_ensure_fb(glamor_priv, pixmap_priv->fbo) != 0) diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c index 6b6e59756..ece7dbe38 100644 --- a/hw/xwayland/xwayland-glamor.c +++ b/hw/xwayland/xwayland-glamor.c @@ -415,7 +415,7 @@ glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, } unsigned int -glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h) +glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h, Bool linear) { return 0; } diff --git a/include/dix-config.h.in b/include/dix-config.h.in index 76f45f535..c2ba4347f 100644 --- a/include/dix-config.h.in +++ b/include/dix-config.h.in @@ -503,6 +503,9 @@ /* Build glamor's GBM-based EGL support */ #undef GLAMOR_HAS_GBM +/* Build glamor/gbm has linear support */ +#undef GLAMOR_HAS_GBM_LINEAR + /* byte order */ #undef X_BYTE_ORDER From a79fbfd707e1d745b670def08287241c87e11c28 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 9 Jun 2015 17:15:44 +1000 Subject: [PATCH 05/14] modesetting: add output master support This allows a glamor enabled master device to have slave USB devices attached. Tested with modesetting on SNB + USB. It relies on the previous patch to export linear buffers from glamor. Acked-by: Eric Anholt Signed-off-by: Dave Airlie --- hw/xfree86/drivers/modesetting/driver.c | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index e90e4b842..092cc5307 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -531,6 +531,38 @@ dispatch_slave_dirty(ScreenPtr pScreen) } } +static void +redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty) +{ + + RegionRec pixregion; + + PixmapRegionInit(&pixregion, dirty->slave_dst); + DamageRegionAppend(&dirty->slave_dst->drawable, &pixregion); + PixmapSyncDirtyHelper(dirty, &pixregion); + + DamageRegionProcessPending(&dirty->slave_dst->drawable); + RegionUninit(&pixregion); +} + +static void +ms_dirty_update(ScreenPtr screen) +{ + RegionPtr region; + PixmapDirtyUpdatePtr ent; + + if (xorg_list_is_empty(&screen->pixmap_dirty_list)) + return; + + xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) { + region = DamageRegion(ent->damage); + if (RegionNotEmpty(region)) { + redisplay_dirty(screen, ent); + DamageEmpty(ent->damage); + } + } +} + static void msBlockHandler(ScreenPtr pScreen, void *pTimeout, void *pReadmask) { @@ -544,6 +576,8 @@ msBlockHandler(ScreenPtr pScreen, void *pTimeout, void *pReadmask) dispatch_slave_dirty(pScreen); else if (ms->dirty_enabled) dispatch_dirty(pScreen); + + ms_dirty_update(pScreen); } static void @@ -727,6 +761,10 @@ PreInit(ScrnInfoPtr pScrn, int flags) if (ret == 0) { if (value & DRM_PRIME_CAP_IMPORT) pScrn->capabilities |= RR_Capability_SinkOutput; +#if GLAMOR_HAS_GBM_LINEAR + if (value & DRM_PRIME_CAP_EXPORT) + pScrn->capabilities |= RR_Capability_SourceOutput; +#endif } #endif drmmode_get_default_bpp(pScrn, &ms->drmmode, &defaultdepth, &defaultbpp); @@ -937,6 +975,23 @@ msShadowInit(ScreenPtr pScreen) return TRUE; } +static Bool +msSharePixmapBacking(PixmapPtr ppix, ScreenPtr screen, void **handle) +{ +#ifdef GLAMOR_HAS_GBM + int ret; + CARD16 stride; + CARD32 size; + ret = glamor_fd_from_pixmap(ppix->drawable.pScreen, ppix, &stride, &size); + if (ret == -1) + return FALSE; + + *handle = (void *)(long)(ret); + return TRUE; +#endif + return FALSE; +} + static Bool msSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle) { @@ -1089,7 +1144,10 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv) ms->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = msBlockHandler; + pScreen->SharePixmapBacking = msSharePixmapBacking; pScreen->SetSharedPixmapBacking = msSetSharedPixmapBacking; + pScreen->StartPixmapTracking = PixmapStartDirtyTracking; + pScreen->StopPixmapTracking = PixmapStopDirtyTracking; if (!xf86CrtcScreenInit(pScreen)) return FALSE; From 1f10ee221edb87561900f5d2b1336db1c4a9f05c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 10 Jun 2015 13:38:39 +1000 Subject: [PATCH 06/14] glamor: egl: add function to back a pixmap with a dma-buf. (v1.1) Rather than create the pixmap, this uses the file descriptor to change an existing pixmaps backing store. This is required for reverse prime slaves, where we create the slave pixmap, then set the backing store. v1.1: use local pScreen (Eric) Reviewed-by: Eric Anholt Signed-off-by: Dave Airlie --- glamor/glamor.h | 19 ++++++++++++++++++ glamor/glamor_egl.c | 49 +++++++++++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/glamor/glamor.h b/glamor/glamor.h index 657354d77..f402d7d62 100644 --- a/glamor/glamor.h +++ b/glamor/glamor.h @@ -218,6 +218,25 @@ extern _X_EXPORT PixmapPtr glamor_pixmap_from_fd(ScreenPtr screen, CARD8 depth, CARD8 bpp); +/* @glamor_back_pixmap_from_fd: Backs an existing pixmap with a dma-buf fd. + * + * @pixmap: Pixmap to change backing for + * @fd: The dma-buf fd to import. + * @width: The width of the buffer. + * @height: The height of the buffer. + * @stride: The stride of the buffer. + * @depth: The depth of the buffer. + * @bpp: The number of bpp of the buffer. + * + * Returns TRUE if successful, FALSE on failure. + * */ +extern _X_EXPORT Bool glamor_back_pixmap_from_fd(PixmapPtr pixmap, + int fd, + CARD16 width, + CARD16 height, + CARD16 stride, + CARD8 depth, + CARD8 bpp); #ifdef GLAMOR_FOR_XORG #define GLAMOR_EGL_MODULE_NAME "glamoregl" diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c index 4c0db6a47..25a9fbef1 100644 --- a/glamor/glamor_egl.c +++ b/glamor/glamor_egl.c @@ -461,19 +461,19 @@ glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, #endif } -_X_EXPORT PixmapPtr -glamor_pixmap_from_fd(ScreenPtr screen, - int fd, - CARD16 width, - CARD16 height, - CARD16 stride, CARD8 depth, CARD8 bpp) +_X_EXPORT Bool +glamor_back_pixmap_from_fd(PixmapPtr pixmap, + int fd, + CARD16 width, + CARD16 height, + CARD16 stride, CARD8 depth, CARD8 bpp) { #ifdef GLAMOR_HAS_GBM + ScreenPtr screen = pixmap->drawable.pScreen; ScrnInfoPtr scrn = xf86ScreenToScrn(screen); struct glamor_egl_screen_private *glamor_egl; struct gbm_bo *bo; EGLImageKHR image; - PixmapPtr pixmap; Bool ret = FALSE; EGLint attribs[] = { @@ -489,10 +489,10 @@ glamor_pixmap_from_fd(ScreenPtr screen, glamor_egl = glamor_egl_get_screen_private(scrn); if (!glamor_egl->dri3_capable) - return NULL; + return FALSE; if (bpp != 32 || !(depth == 24 || depth == 32) || width == 0 || height == 0) - return NULL; + return FALSE; attribs[1] = width; attribs[3] = height; @@ -504,29 +504,48 @@ glamor_pixmap_from_fd(ScreenPtr screen, NULL, attribs); if (image == EGL_NO_IMAGE_KHR) - return NULL; + return FALSE; /* EGL_EXT_image_dma_buf_import can impose restrictions on the * usage of the image. Use gbm_bo to bypass the limitations. */ - bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0); eglDestroyImageKHR(glamor_egl->display, image); if (!bo) - return NULL; + return FALSE; - pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0); screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL); ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo); gbm_bo_destroy(bo); if (ret) - return pixmap; - else { + return TRUE; + return FALSE; +#else + return FALSE; +#endif +} + +_X_EXPORT PixmapPtr +glamor_pixmap_from_fd(ScreenPtr screen, + int fd, + CARD16 width, + CARD16 height, + CARD16 stride, CARD8 depth, CARD8 bpp) +{ +#ifdef GLAMOR_HAS_GBM + PixmapPtr pixmap; + Bool ret; + + pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0); + ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height, + stride, depth, bpp); + if (ret == FALSE) { screen->DestroyPixmap(pixmap); return NULL; } + return pixmap; #else return NULL; #endif From 7328fb3f2b468048faf4ed4c29db720b5bf00b05 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 10 Jun 2015 13:41:02 +1000 Subject: [PATCH 07/14] modesetting: reverse prime support (v1.1) This adds support for reverse prime to the modesetting driver. Reverse prime is where we have two GPUs in the display chain, but the second GPU can't scanout from the shared pixmap, so needs an extra copy to the on screen pixmap. This allows modesetting to support this scenario while still supporting the USB offload one. v1.1: fix comment + ret = bits (Eric) Reviewed-by: Eric Anholt Signed-off-by: Dave Airlie --- hw/xfree86/drivers/modesetting/driver.c | 17 ++++- .../drivers/modesetting/drmmode_display.c | 74 +++++++++++++++++-- .../drivers/modesetting/drmmode_display.h | 4 +- 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 092cc5307..f421668c9 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -572,7 +572,7 @@ msBlockHandler(ScreenPtr pScreen, void *pTimeout, void *pReadmask) pScreen->BlockHandler(pScreen, pTimeout, pReadmask); ms->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = msBlockHandler; - if (pScreen->isGPU) + if (pScreen->isGPU && !ms->drmmode.reverse_prime_offload_mode) dispatch_slave_dirty(pScreen); else if (ms->dirty_enabled) dispatch_dirty(pScreen); @@ -999,10 +999,18 @@ msSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle) ScrnInfoPtr scrn = xf86ScreenToScrn(screen); modesettingPtr ms = modesettingPTR(scrn); Bool ret; - int size = ppix->devKind * ppix->drawable.height; int ihandle = (int) (long) fd_handle; - ret = drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, ppix->devKind, size); + if (ms->drmmode.reverse_prime_offload_mode) { + ret = glamor_back_pixmap_from_fd(ppix, ihandle, + ppix->drawable.width, + ppix->drawable.height, + ppix->devKind, ppix->drawable.depth, + ppix->drawable.bitsPerPixel); + } else { + int size = ppix->devKind * ppix->drawable.height; + ret = drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, ppix->devKind, size); + } if (ret == FALSE) return ret; @@ -1190,6 +1198,9 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to initialize the Present extension.\n"); } + /* enable reverse prime if we are a GPU screen, and accelerated */ + if (pScreen->isGPU) + ms->drmmode.reverse_prime_offload_mode = TRUE; } #endif diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index f3c9909ef..506ea2426 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -50,6 +50,7 @@ #include "driver.h" +static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height); static int drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo) { @@ -343,10 +344,14 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, fb_id = drmmode->fb_id; if (crtc->randr_crtc->scanout_pixmap) { - msPixmapPrivPtr ppriv = - msGetPixmapPriv(drmmode, crtc->randr_crtc->scanout_pixmap); - fb_id = ppriv->fb_id; - x = y = 0; + if (!drmmode->reverse_prime_offload_mode) { + msPixmapPrivPtr ppriv = + msGetPixmapPriv(drmmode, crtc->randr_crtc->scanout_pixmap); + fb_id = ppriv->fb_id; + x = 0; + } else + x = drmmode_crtc->prime_pixmap_x; + y = 0; } else if (drmmode_crtc->rotate_fb_id) { fb_id = drmmode_crtc->rotate_fb_id; @@ -502,7 +507,54 @@ drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green, } static Bool -drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) +drmmode_set_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix) +{ + ScreenPtr screen = xf86ScrnToScreen(crtc->scrn); + PixmapPtr screenpix = screen->GetScreenPixmap(screen); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + int c, total_width = 0, max_height = 0, this_x = 0; + + if (!ppix) { + if (crtc->randr_crtc->scanout_pixmap) + PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix); + drmmode_crtc->prime_pixmap_x = 0; + return TRUE; + } + /* iterate over all the attached crtcs to work out the bounding box */ + for (c = 0; c < xf86_config->num_crtc; c++) { + xf86CrtcPtr iter = xf86_config->crtc[c]; + if (!iter->enabled && iter != crtc) + continue; + if (iter == crtc) { + this_x = total_width; + total_width += ppix->drawable.width; + if (max_height < ppix->drawable.height) + max_height = ppix->drawable.height; + } else { + total_width += iter->mode.HDisplay; + if (max_height < iter->mode.VDisplay) + max_height = iter->mode.VDisplay; + } + } + + if (total_width != screenpix->drawable.width || + max_height != screenpix->drawable.height) { + + if (!drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height)) + return FALSE; + + screenpix = screen->GetScreenPixmap(screen); + screen->width = screenpix->drawable.width = total_width; + screen->height = screenpix->drawable.height = max_height; + } + drmmode_crtc->prime_pixmap_x = this_x; + PixmapStartDirtyTracking2(ppix, screenpix, 0, 0, this_x, 0); + return TRUE; +} + +static Bool +drmmode_set_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix) { drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; @@ -543,6 +595,18 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) return TRUE; } +static Bool +drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + + if (drmmode->reverse_prime_offload_mode) + return drmmode_set_scanout_pixmap_gpu(crtc, ppix); + else + return drmmode_set_scanout_pixmap_cpu(crtc, ppix); +} + static void * drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height) { diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index b0e45b6e0..85a0ec435 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -79,6 +79,8 @@ typedef struct { uint32_t triple_buffer_name; DevPrivateKeyRec pixmapPrivateKeyRec; + + Bool reverse_prime_offload_mode; } drmmode_rec, *drmmode_ptr; typedef struct { @@ -93,7 +95,7 @@ typedef struct { drmmode_bo rotate_bo; unsigned rotate_fb_id; - + unsigned prime_pixmap_x; /** * @{ MSC (vblank count) handling for the PRESENT extension. * From f6853baebaec6a68078fa7f90486e9547d59dcbd Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Sun, 8 Feb 2015 17:21:58 -0800 Subject: [PATCH 08/14] modesetting: Improve the ms_flush_drm_events() API. Previously, ms_flush_drm_events() returned a boolean value, and it was very easy to interpret the meaning incorrectly. Now, we return an integer value. The possible outcomes of this call are: - poll() raised an error (formerly TRUE, now -1 - poll's return value) - poll() said there are no events (formerly TRUE, now 0). - drmHandleEvent() raised an error (formerly FALSE, now the negative value returned by drmHandleEvent). - An event was successfully handled (formerly TRUE, now 1). The nice part is that this allows you to distinguish errors (< 0), nothing to do (= 0), and success (1). We no longer conflate errors with success. v2: Change ms_present_queue_vblank to < 0 instead of <= 0, fixing an unintentional behavior change. libdrm may return EBUSY if it's received EINTR for more than a second straight; just keep retrying in that case. Suggested by Jasper St. Pierre. Reviewed-by: Dave Airlie Signed-off-by: Kenneth Graunke --- hw/xfree86/drivers/modesetting/present.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c index 359e11316..43df148d1 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -72,8 +72,11 @@ ms_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc) /* * Flush the DRM event queue when full; makes space for new events. + * + * Returns a negative value on error, 0 if there was nothing to process, + * or 1 if we handled any events. */ -static Bool +static int ms_flush_drm_events(ScreenPtr screen) { ScrnInfoPtr scrn = xf86ScreenToScrn(screen); @@ -86,10 +89,19 @@ ms_flush_drm_events(ScreenPtr screen) r = poll(&p, 1, 0); } while (r == -1 && (errno == EINTR || errno == EAGAIN)); + /* If there was an error, r will be < 0. Return that. If there was + * nothing to process, r == 0. Return that. + */ if (r <= 0) - return TRUE; + return r; - return drmHandleEvent(ms->fd, &ms->event_context) >= 0; + /* Try to handle the event. If there was an error, return it. */ + r = drmHandleEvent(ms->fd, &ms->event_context); + if (r < 0) + return r; + + /* Otherwise return 1 to indicate that we handled an event. */ + return 1; } /* @@ -159,7 +171,10 @@ ms_present_queue_vblank(RRCrtcPtr crtc, ret = drmWaitVBlank(ms->fd, &vbl); if (!ret) break; - if (errno != EBUSY || !ms_flush_drm_events(screen)) + /* If we hit EBUSY, then try to flush events. If we can't, then + * this is an error. + */ + if (errno != EBUSY || ms_flush_drm_events(screen) < 0) return BadAlloc; } DebugPresent(("\t\tmq %lld seq %u msc %llu (hw msc %u)\n", From f2171d0a20d3b3858a282c51c1561432de1b29ef Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Tue, 6 Jan 2015 21:02:44 -0800 Subject: [PATCH 09/14] modesetting: Make ms_crtc_on non-static. I want to use this in present.c. Reviewed-by: Dave Airlie Reviewed-by: Eric Anholt Signed-off-by: Kenneth Graunke --- hw/xfree86/drivers/modesetting/driver.h | 2 ++ hw/xfree86/drivers/modesetting/vblank.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 3decc3eea..4b6ae87fa 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -118,6 +118,8 @@ void ms_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data); +Bool ms_crtc_on(xf86CrtcPtr crtc); + xf86CrtcPtr ms_dri2_crtc_covering_drawable(DrawablePtr pDraw); xf86CrtcPtr ms_covering_crtc(ScrnInfoPtr scrn, BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret); diff --git a/hw/xfree86/drivers/modesetting/vblank.c b/hw/xfree86/drivers/modesetting/vblank.c index a342662a7..91cfcf2d5 100644 --- a/hw/xfree86/drivers/modesetting/vblank.c +++ b/hw/xfree86/drivers/modesetting/vblank.c @@ -88,7 +88,7 @@ static int ms_box_area(BoxPtr box) return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1); } -static Bool +Bool ms_crtc_on(xf86CrtcPtr crtc) { drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; From b8ccc5d36b0436bac57f07969ff3eb8d479a8511 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Tue, 13 Jan 2015 17:00:28 -0800 Subject: [PATCH 10/14] glamor: Add a new glamor_gbm_bo_from_pixmap() function. v2: Rebase on commit e0788a03144 (drop "base"). Reviewed-by: Eric Anholt Reviewed-by: Dave Airlie --- glamor/glamor.h | 15 +++++++++++ glamor/glamor_egl.c | 63 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/glamor/glamor.h b/glamor/glamor.h index f402d7d62..0931bbccd 100644 --- a/glamor/glamor.h +++ b/glamor/glamor.h @@ -198,6 +198,21 @@ extern _X_EXPORT int glamor_fd_from_pixmap(ScreenPtr screen, extern _X_EXPORT int glamor_name_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size); +/* @glamor_gbm_bo_from_pixmap: Get a GBM bo from a pixmap. + * + * @screen: Current screen pointer. + * @pixmap: The pixmap from which we want the fd. + * @stride, @size: Pointers to fill the stride and size of the + * buffer associated to the fd. + * + * the pixmap and the buffer represented by the gbm_bo will share the same + * content. + * + * Returns the gbm_bo on success, NULL on error. + * */ +extern _X_EXPORT void *glamor_gbm_bo_from_pixmap(ScreenPtr screen, + PixmapPtr pixmap); + /* @glamor_pixmap_from_fd: Creates a pixmap to wrap a dma-buf fd. * * @screen: Current screen pointer. diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c index 25a9fbef1..e01f723fc 100644 --- a/glamor/glamor_egl.c +++ b/glamor/glamor_egl.c @@ -395,13 +395,10 @@ glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name) } #endif -int -glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, - PixmapPtr pixmap, - unsigned int tex, - Bool want_name, CARD16 *stride, CARD32 *size) -{ #ifdef GLAMOR_HAS_GBM +static void * +_get_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, unsigned int tex) +{ ScrnInfoPtr scrn = xf86ScreenToScrn(screen); struct glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); @@ -410,7 +407,6 @@ glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, struct glamor_egl_screen_private *glamor_egl; EGLImageKHR image; struct gbm_bo *bo; - int fd = -1; EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, @@ -430,13 +426,64 @@ glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, (EGLClientBuffer) (uintptr_t) tex, attribs); if (image == EGL_NO_IMAGE_KHR) - goto failure; + return NULL; glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); glamor_egl_set_pixmap_image(pixmap, image); } bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0); + if (!bo) + return NULL; + + pixmap->devKind = gbm_bo_get_stride(bo); + + return bo; +} +#endif + +void * +glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap) +{ +#ifdef GLAMOR_HAS_GBM + glamor_screen_private *glamor_priv = + glamor_get_screen_private(pixmap->drawable.pScreen); + glamor_pixmap_private *pixmap_priv = + glamor_get_pixmap_private(pixmap); + + pixmap_priv = glamor_get_pixmap_private(pixmap); + if (pixmap_priv == NULL || !glamor_priv->dri3_enabled) + return NULL; + switch (pixmap_priv->type) { + case GLAMOR_TEXTURE_DRM: + case GLAMOR_TEXTURE_ONLY: + if (!glamor_pixmap_ensure_fbo(pixmap, GL_RGBA, 0)) + return NULL; + return _get_gbm_bo_from_pixmap(screen, pixmap, + pixmap_priv->fbo->tex); + default: + break; + } + return NULL; +#else + return NULL; +#endif +} + +int +glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, + PixmapPtr pixmap, + unsigned int tex, + Bool want_name, CARD16 *stride, CARD32 *size) +{ +#ifdef GLAMOR_HAS_GBM + struct glamor_egl_screen_private *glamor_egl; + struct gbm_bo *bo; + int fd = -1; + + glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); + + bo = _get_gbm_bo_from_pixmap(screen, pixmap, tex); if (!bo) goto failure; From bf262b43007050180d336defd48251de80894801 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Mon, 26 Jan 2015 21:25:58 -0800 Subject: [PATCH 11/14] modesetting: Implement an ms_drm_abort_seq() function. This is a specialization of ms_drm_abort that matches based on the drm event queue's sequence number. Based on code by Keith Packard. Reviewed-by: Eric Anholt Reviewed-by: Dave Airlie Signed-off-by: Kenneth Graunke --- hw/xfree86/drivers/modesetting/driver.h | 1 + hw/xfree86/drivers/modesetting/vblank.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 4b6ae87fa..843a105ed 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -117,6 +117,7 @@ uint32_t ms_drm_queue_alloc(xf86CrtcPtr crtc, void ms_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data); +void ms_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq); Bool ms_crtc_on(xf86CrtcPtr crtc); diff --git a/hw/xfree86/drivers/modesetting/vblank.c b/hw/xfree86/drivers/modesetting/vblank.c index 91cfcf2d5..776dcef9b 100644 --- a/hw/xfree86/drivers/modesetting/vblank.c +++ b/hw/xfree86/drivers/modesetting/vblank.c @@ -323,6 +323,22 @@ ms_drm_abort_scrn(ScrnInfoPtr scrn) } } +/** + * Abort by drm queue sequence number. + */ +void +ms_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq) +{ + struct ms_drm_queue *q, *tmp; + + xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) { + if (q->seq == seq) { + ms_drm_abort_one(q); + break; + } + } +} + /* * Externally usable abort function that uses a callback to match a single * queued entry to abort From edec6394a47be590f3133f6a90186356afd00829 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 26 Jun 2015 09:19:37 +1000 Subject: [PATCH 12/14] modesetting: drop unused struct in vblank.c this isn't used anywhere here. Reviewed-by: Eric Anholt Signed-off-by: Dave Airlie --- hw/xfree86/drivers/modesetting/vblank.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/vblank.c b/hw/xfree86/drivers/modesetting/vblank.c index 776dcef9b..0b7bf9d73 100644 --- a/hw/xfree86/drivers/modesetting/vblank.c +++ b/hw/xfree86/drivers/modesetting/vblank.c @@ -50,11 +50,6 @@ static struct xorg_list ms_drm_queue; static uint32_t ms_drm_seq; -struct ms_pageflip { - ScreenPtr screen; - Bool crtc_for_msc_ust; -}; - static void ms_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) { dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; From 4342369e843ca2c6ca0a8c42475893cffb077a54 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 26 Jun 2015 09:20:13 +1000 Subject: [PATCH 13/14] modesetting: don't try and load dri2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we are shipped with the server and the server has it built-in, don't bother trying to load it. Don't remove or invert the if statement on purpose as a later patch adds stuff in here. Reviewed-by: Michel Dänzer Reviewed-by: Eric Anholt Signed-off-by: Dave Airlie --- hw/xfree86/drivers/modesetting/driver.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index f421668c9..ae562a1e1 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -820,7 +820,6 @@ PreInit(ScrnInfoPtr pScrn, int flags) try_enable_glamor(pScrn); if (ms->drmmode.glamor) { - xf86LoadSubModule(pScrn, "dri2"); } else { Bool prefer_shadow = TRUE; From 13c7d53df8dac45ea2a685826cd45a39bcb51657 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Mon, 26 Jan 2015 21:29:23 -0800 Subject: [PATCH 14/14] modesetting: Implement page flipping support for Present. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on code by Keith Packard, Eric Anholt, and Jason Ekstrand. v2: - Fix double free and flip_count underrun (caught by Mario Kleiner). - Don't leak flip_vblank_event on the error_out path (Mario). - Use the updated ms_flush_drm_events API (Mario, Ken). v3: Hack around DPMS shenanigans. If all monitors are DPMS off, then there is no active framebuffer; attempting to pageflip will hit the error_undo paths, causing us to drmModeRmFB with no framebuffer, which confuses the kernel into doing full modesets and generally breaks things. To avoid this, make ms_present_check_flip check that some CRTCs are enabled and DPMS on. This is an ugly hack that would get better with atomic modesetting, or some core Present work. v4: - Don't do pageflipping if CRTCs are rotated (caught by Jason Ekstrand). - Make pageflipping optional (Option "PageFlip" in xorg.conf.d), but enabled by default. v5: Initialize num_crtcs_on to 0 (caught by Michel Dänzer). [airlied: took over] v6: merge async flip support from Mario Kleiner free sequence after failed vblank queue handle unflip while DPMS'ed off (Michel) move flip tracking into its own structure, and fix up reference counting issues, and add comments. Signed-off-by: Dave Airlie Acked-by: Eric Anholt Signed-off-by: Kenneth Graunke --- hw/xfree86/drivers/modesetting/driver.c | 6 + hw/xfree86/drivers/modesetting/driver.h | 6 + .../drivers/modesetting/drmmode_display.c | 43 +- .../drivers/modesetting/drmmode_display.h | 8 +- hw/xfree86/drivers/modesetting/present.c | 429 +++++++++++++++++- 5 files changed, 485 insertions(+), 7 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index ae562a1e1..860333863 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -123,6 +123,7 @@ typedef enum { OPTION_DEVICE_PATH, OPTION_SHADOW_FB, OPTION_ACCEL_METHOD, + OPTION_PAGEFLIP, } modesettingOpts; static const OptionInfoRec Options[] = { @@ -130,6 +131,7 @@ static const OptionInfoRec Options[] = { {OPTION_DEVICE_PATH, "kmsdev", OPTV_STRING, {0}, FALSE}, {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE}, + {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; @@ -820,6 +822,8 @@ PreInit(ScrnInfoPtr pScrn, int flags) try_enable_glamor(pScrn); if (ms->drmmode.glamor) { + ms->drmmode.pageflip = + xf86ReturnOptValBool(ms->Options, OPTION_PAGEFLIP, TRUE); } else { Bool prefer_shadow = TRUE; @@ -836,6 +840,8 @@ PreInit(ScrnInfoPtr pScrn, int flags) "ShadowFB: preferred %s, enabled %s\n", prefer_shadow ? "YES" : "NO", ms->drmmode.shadow_enable ? "YES" : "NO"); + + ms->drmmode.pageflip = FALSE; } if (drmmode_pre_init(pScrn, &ms->drmmode, pScrn->bitsPerPixel / 8) == FALSE) { diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 843a105ed..9ae4966fd 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -101,6 +101,12 @@ typedef struct _modesettingRec { drmEventContext event_context; + /** + * Page flipping stuff. + * @{ + */ + /** @} */ + DamagePtr damage; Bool dirty_enabled; diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 506ea2426..8dbac07f2 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -51,7 +51,8 @@ #include "driver.h" static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height); -static int + +int drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo) { int ret; @@ -72,7 +73,7 @@ drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo) return 0; } -static uint32_t +uint32_t drmmode_bo_get_pitch(drmmode_bo *bo) { #ifdef GLAMOR_HAS_GBM @@ -142,6 +143,35 @@ drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo, return bo->dumb != NULL; } +Bool +drmmode_bo_for_pixmap(drmmode_ptr drmmode, drmmode_bo *bo, PixmapPtr pixmap) +{ + ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn); + uint16_t pitch; + uint32_t size; + int fd; + +#ifdef GLAMOR_HAS_GBM + if (drmmode->glamor) { + bo->gbm = glamor_gbm_bo_from_pixmap(screen, pixmap); + bo->dumb = NULL; + return bo->gbm != NULL; + } +#endif + + fd = glamor_fd_from_pixmap(screen, pixmap, &pitch, &size); + if (fd < 0) { + xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR, + "Failed to get fd for flip to new front.\n"); + return FALSE; + } + + bo->dumb = dumb_get_bo_from_fd(drmmode->fd, fd, pitch, size); + close(fd); + + return bo->dumb != NULL; +} + Bool drmmode_SetSlaveBO(PixmapPtr ppix, drmmode_ptr drmmode, int fd_handle, int pitch, int size) @@ -368,6 +398,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, if (crtc->scrn->pScreen) xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen); + drmmode_crtc->need_modeset = FALSE; crtc->funcs->dpms(crtc, DPMSModeOn); /* go through all the outputs and force DPMS them back on? */ @@ -1003,6 +1034,7 @@ static void drmmode_output_dpms(xf86OutputPtr output, int mode) { drmmode_output_private_ptr drmmode_output = output->driver_private; + xf86CrtcPtr crtc = output->crtc; drmModeConnectorPtr koutput = drmmode_output->mode_output; drmmode_ptr drmmode = drmmode_output->drmmode; @@ -1011,6 +1043,13 @@ drmmode_output_dpms(xf86OutputPtr output, int mode) drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, drmmode_output->dpms_enum_id, mode); + + if (mode == DPMSModeOn && crtc) { + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + if (drmmode_crtc->need_modeset) + drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, + crtc->x, crtc->y); + } return; } diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index 85a0ec435..fe363c577 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -46,7 +46,6 @@ typedef struct { typedef struct { int fd; unsigned fb_id; - unsigned old_fb_id; drmModeFBPtr mode_fb; int cpp; ScrnInfoPtr scrn; @@ -63,6 +62,8 @@ typedef struct { Bool glamor; Bool shadow_enable; + /** Is Option "PageFlip" enabled? */ + Bool pageflip; void *shadow_fb; /** @@ -107,6 +108,8 @@ typedef struct { uint32_t msc_prev; uint64_t msc_high; /** @} */ + + Bool need_modeset; } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; typedef struct { @@ -141,6 +144,9 @@ extern DevPrivateKeyRec msPixmapPrivateKeyRec; #define msGetPixmapPriv(drmmode, p) ((msPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &(drmmode)->pixmapPrivateKeyRec)) +Bool drmmode_bo_for_pixmap(drmmode_ptr drmmode, drmmode_bo *bo, PixmapPtr pixmap); +int drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo); +uint32_t drmmode_bo_get_pitch(drmmode_bo *bo); uint32_t drmmode_bo_get_handle(drmmode_bo *bo); Bool drmmode_glamor_handle_new_screen_pixmap(drmmode_ptr drmmode); void *drmmode_map_slave_bo(drmmode_ptr drmmode, msPixmapPrivPtr ppriv); diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c index 43df148d1..090539861 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -44,6 +44,7 @@ #include #include "driver.h" +#include "drmmode_display.h" #if 0 #define DebugPresent(x) ErrorF x @@ -174,8 +175,10 @@ ms_present_queue_vblank(RRCrtcPtr crtc, /* If we hit EBUSY, then try to flush events. If we can't, then * this is an error. */ - if (errno != EBUSY || ms_flush_drm_events(screen) < 0) + if (errno != EBUSY || ms_flush_drm_events(screen) < 0) { + ms_drm_abort_seq(scrn, seq); return BadAlloc; + } } DebugPresent(("\t\tmq %lld seq %u msc %llu (hw msc %u)\n", (long long) event_id, seq, (long long) msc, @@ -221,6 +224,413 @@ ms_present_flush(WindowPtr window) #endif } +#ifdef GLAMOR + +/* + * Event data for an in progress flip. + * This contains a pointer to the vblank event, + * and information about the flip in progress. + * a reference to this is stored in the per-crtc + * flips. + */ +struct ms_flipdata { + ScreenPtr screen; + struct ms_present_vblank_event *event; + /* number of CRTC events referencing this */ + int flip_count; + uint64_t fe_msc; + uint64_t fe_usec; + uint32_t old_fb_id; +}; + +/* + * Per crtc pageflipping infomation, + * These are submitted to the queuing code + * one of them per crtc per flip. + */ +struct ms_crtc_pageflip { + Bool on_reference_crtc; + /* reference to the ms_flipdata */ + struct ms_flipdata *flipdata; +}; + +/** + * Free an ms_crtc_pageflip. + * + * Drops the reference count on the flipdata. + */ +static void +ms_present_flip_free(struct ms_crtc_pageflip *flip) +{ + struct ms_flipdata *flipdata = flip->flipdata; + + free(flip); + if (--flipdata->flip_count > 0) + return; + free(flipdata); +} + +/** + * Callback for the DRM event queue when a single flip has completed + * + * Once the flip has been completed on all pipes, notify the + * extension code telling it when that happened + */ +static void +ms_flip_handler(uint64_t msc, uint64_t ust, void *data) +{ + struct ms_crtc_pageflip *flip = data; + ScreenPtr screen = flip->flipdata->screen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + struct ms_flipdata *flipdata = flip->flipdata; + + DebugPresent(("\t\tms:fh %lld c %d msc %llu ust %llu\n", + (long long) flipdata->event->event_id, + flipdata->flip_count, + (long long) msc, (long long) ust)); + + if (flip->on_reference_crtc) { + flipdata->fe_msc = msc; + flipdata->fe_usec = ust; + } + + if (flipdata->flip_count == 1) { + DebugPresent(("\t\tms:fc %lld c %d msc %llu ust %llu\n", + (long long) flipdata->event->event_id, + flipdata->flip_count, + (long long) flipdata->fe_msc, (long long) flipdata->fe_usec)); + + + ms_present_vblank_handler(flipdata->fe_msc, + flipdata->fe_usec, + flipdata->event); + + drmModeRmFB(ms->fd, flipdata->old_fb_id); + } + ms_present_flip_free(flip); +} + +/* + * Callback for the DRM queue abort code. A flip has been aborted. + */ +static void +ms_present_flip_abort(void *data) +{ + struct ms_crtc_pageflip *flip = data; + struct ms_flipdata *flipdata = flip->flipdata; + + DebugPresent(("\t\tms:fa %lld c %d\n", (long long) flipdata->event->event_id, flipdata->flip_count)); + + if (flipdata->flip_count == 1) + free(flipdata->event); + + ms_present_flip_free(flip); +} + +static Bool +queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc, + struct ms_flipdata *flipdata, + int ref_crtc_vblank_pipe, uint32_t flags) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + struct ms_crtc_pageflip *flip; + uint32_t seq; + int err; + + flip = calloc(1, sizeof(struct ms_crtc_pageflip)); + if (flip == NULL) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue: carrier alloc failed.\n"); + return FALSE; + } + + /* Only the reference crtc will finally deliver its page flip + * completion event. All other crtc's events will be discarded. + */ + flip->on_reference_crtc = (drmmode_crtc->vblank_pipe == ref_crtc_vblank_pipe); + flip->flipdata = flipdata; + + seq = ms_drm_queue_alloc(crtc, flip, ms_flip_handler, ms_present_flip_abort); + if (!seq) { + free(flip); + return FALSE; + } + + DebugPresent(("\t\tms:fq %lld c %d -> %d seq %llu\n", + (long long) flipdata->event->event_id, + flipdata->flip_count, flipdata->flip_count + 1, + (long long) seq)); + + /* take a reference on flipdata for use in flip */ + flipdata->flip_count++; + + while (drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id, + ms->drmmode.fb_id, flags, (void *) (uintptr_t) seq)) { + err = errno; + /* We may have failed because the event queue was full. Flush it + * and retry. If there was nothing to flush, then we failed for + * some other reason and should just return an error. + */ + if (ms_flush_drm_events(screen) <= 0) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue failed: %s\n", strerror(err)); + /* Aborting will also decrement flip_count and free(flip). */ + ms_drm_abort_seq(scrn, seq); + return FALSE; + } + + /* We flushed some events, so try again. */ + xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue retry\n"); + } + + /* The page flip succeded. */ + return TRUE; +} + + +static Bool +ms_do_pageflip(ScreenPtr screen, + PixmapPtr new_front, + struct ms_present_vblank_event *event, + int ref_crtc_vblank_pipe, + Bool async) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + drmmode_bo new_front_bo; + uint32_t flags; + int i; + struct ms_flipdata *flipdata; + glamor_block_handler(screen); + + new_front_bo.gbm = glamor_gbm_bo_from_pixmap(screen, new_front); + new_front_bo.dumb = NULL; + if (!new_front_bo.gbm) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to get GBM bo for flip to new front.\n"); + return FALSE; + } + + flipdata = calloc(1, sizeof(struct ms_flipdata)); + if (!flipdata) { + drmmode_bo_destroy(&ms->drmmode, &new_front_bo); + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to allocate flipdata.\n"); + return FALSE; + } + + flipdata->event = event; + flipdata->screen = screen; + + /* + * Take a local reference on flipdata. + * if the first flip fails, the sequence abort + * code will free the crtc flip data, and drop + * it's reference which would cause this to be + * freed when we still required it. + */ + flipdata->flip_count++; + + /* Create a new handle for the back buffer */ + flipdata->old_fb_id = ms->drmmode.fb_id; + if (drmModeAddFB(ms->fd, scrn->virtualX, scrn->virtualY, + scrn->depth, scrn->bitsPerPixel, + drmmode_bo_get_pitch(&new_front_bo), + drmmode_bo_get_handle(&new_front_bo), &ms->drmmode.fb_id)) { + goto error_out; + } + + drmmode_bo_destroy(&ms->drmmode, &new_front_bo); + + flags = DRM_MODE_PAGE_FLIP_EVENT; + if (async) + flags |= DRM_MODE_PAGE_FLIP_ASYNC; + + /* Queue flips on all enabled CRTCs. + * + * Note that if/when we get per-CRTC buffers, we'll have to update this. + * Right now it assumes a single shared fb across all CRTCs, with the + * kernel fixing up the offset of each CRTC as necessary. + * + * Also, flips queued on disabled or incorrectly configured displays + * may never complete; this is a configuration error. + */ + for (i = 0; i < config->num_crtc; i++) { + xf86CrtcPtr crtc = config->crtc[i]; + + if (!ms_crtc_on(crtc)) + continue; + + if (!queue_flip_on_crtc(screen, crtc, flipdata, + ref_crtc_vblank_pipe, + flags)) { + goto error_undo; + } + } + + /* + * Do we have more than our local reference, + * if so and no errors, then drop our local + * reference and return now. + */ + if (flipdata->flip_count > 1) { + flipdata->flip_count--; + return TRUE; + } + +error_undo: + + /* + * Have we just got the local reference? + * free the framebuffer if so since nobody successfully + * submitted anything + */ + if (flipdata->flip_count == 1) { + drmModeRmFB(ms->fd, ms->drmmode.fb_id); + ms->drmmode.fb_id = flipdata->old_fb_id; + } + +error_out: + xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", + strerror(errno)); + /* if only the local reference - free the structure, + * else drop the local reference and return */ + if (flipdata->flip_count == 1) + free(flipdata); + else + flipdata->flip_count--; + + return FALSE; +} + +/* + * 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) +{ + ScreenPtr screen = window->drawable.pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int num_crtcs_on = 0; + int i; + + if (!ms->drmmode.pageflip) + return FALSE; + + if (!scrn->vtSema) + return FALSE; + + for (i = 0; i < config->num_crtc; i++) { + drmmode_crtc_private_ptr drmmode_crtc = config->crtc[i]->driver_private; + + /* Don't do pageflipping if CRTCs are rotated. */ + if (drmmode_crtc->rotate_bo.gbm) + return FALSE; + + if (ms_crtc_on(config->crtc[i])) + num_crtcs_on++; + } + + /* We can't do pageflipping if all the CRTCs are off. */ + if (num_crtcs_on == 0) + return FALSE; + + /* Check stride, can't change that on flip */ + if (pixmap->devKind != drmmode_bo_get_pitch(&ms->drmmode.front_bo)) + return FALSE; + + /* Make sure there's a bo we can get to */ + /* XXX: actually do this. also...is it sufficient? + * if (!glamor_get_pixmap_private(pixmap)) + * return FALSE; + */ + + return TRUE; +} + +/* + * 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) +{ + ScreenPtr screen = crtc->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + xf86CrtcPtr xf86_crtc = crtc->devPrivate; + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; + Bool ret; + struct ms_present_vblank_event *event; + + if (!ms_present_check_flip(crtc, screen->root, pixmap, sync_flip)) + return FALSE; + + event = calloc(1, sizeof(struct ms_present_vblank_event)); + if (!event) + return FALSE; + + event->event_id = event_id; + ret = ms_do_pageflip(screen, pixmap, event, drmmode_crtc->vblank_pipe, !sync_flip); + if (!ret) + xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n"); + + return ret; +} + +/* + * Queue a flip back to the normal frame buffer + */ +static void +ms_present_unflip(ScreenPtr screen, uint64_t event_id) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + PixmapPtr pixmap = screen->GetScreenPixmap(screen); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int i; + struct ms_present_vblank_event *event; + + event = calloc(1, sizeof(struct ms_present_vblank_event)); + if (!event) + return; + + event->event_id = event_id; + + if (ms_present_check_flip(NULL, screen->root, pixmap, TRUE) && + ms_do_pageflip(screen, pixmap, event, -1, FALSE)) { + return; + } + + for (i = 0; i < config->num_crtc; i++) { + xf86CrtcPtr crtc = config->crtc[i]; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (!crtc->enabled) + continue; + + if (drmmode_crtc->dpms_mode == DPMSModeOn) + crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, + crtc->x, crtc->y); + else + drmmode_crtc->need_modeset = TRUE; + } + + present_event_notify(event_id, 0, 0); +} +#endif + static present_screen_info_rec ms_present_screen_info = { .version = PRESENT_SCREEN_INFO_VERSION, @@ -231,13 +641,24 @@ static present_screen_info_rec ms_present_screen_info = { .flush = ms_present_flush, .capabilities = PresentCapabilityNone, - .check_flip = 0, - .flip = 0, - .unflip = 0, + .check_flip = ms_present_check_flip, +#ifdef GLAMOR + .flip = ms_present_flip, + .unflip = ms_present_unflip, +#endif }; Bool ms_present_screen_init(ScreenPtr screen) { + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + uint64_t value; + int ret; + + ret = drmGetCap(ms->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); + if (ret == 0 && value == 1) + ms_present_screen_info.capabilities |= PresentCapabilityAsync; + return present_screen_init(screen, &ms_present_screen_info); }