[Nouveau] [RFC PATCH] Support running nested in a Mir compositor

christopher.halse.rogers at canonical.com christopher.halse.rogers at canonical.com
Mon Jul 22 00:51:22 PDT 2013


From: Christopher James Halse Rogers <raof at ubuntu.com>

Barring some (admittedly significant) missing optimisations¹ this is reasonably
complete, but can't be applied until the Xserver patch has landed,
and that needs more work.

This demonstrates the approach, however.

There's probably some code to be shared with XWayland support, around the
output handling (or lack thereof) and possibly integration with the underlying
compositor for SwapBuffers etc.

¹: Such as not doing a fullscreen blit on all damage, integration with
DRI2 and SwapBuffers to avoid copies, etc.

Signed-off-by: Christopher James Halse Rogers <raof at ubuntu.com>
---
 src/nouveau_dri2.c |  22 ++++++-
 src/nv_driver.c    | 170 +++++++++++++++++++++++++++++++++++++++++++++++++----
 src/nv_type.h      |  10 ++++
 3 files changed, 188 insertions(+), 14 deletions(-)

diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index 3785956..2ad9932 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -267,7 +267,7 @@ can_exchange(DrawablePtr draw, PixmapPtr dst_pix, PixmapPtr src_pix)
 	NVPtr pNv = NVPTR(scrn);
 	int i;
 
-	if (!xf86_config->num_crtc)
+	if (xorgMir || !xf86_config->num_crtc)
 		return FALSE;
 
 	for (i = 0; i < xf86_config->num_crtc; i++) {
@@ -290,7 +290,7 @@ can_sync_to_vblank(DrawablePtr draw)
 	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
 	NVPtr pNv = NVPTR(scrn);
 
-	return pNv->glx_vblank &&
+	return pNv->glx_vblank && !xorgMir &&
 		nv_window_belongs_to_crtc(scrn, draw->x, draw->y,
 					  draw->width, draw->height);
 }
@@ -766,6 +766,19 @@ nouveau_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
 	free(flip);
 }
 
+#if DRI2INFOREC_VERSION >= 8 && defined(XMIR)
+static int nouveau_dri2_auth_magic(ScreenPtr pScreen, uint32_t magic)
+{
+    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+    NVPtr pNv = NVPTR(pScrn);
+
+    if (xorgMir)
+	return xmir_auth_drm_magic(pNv->xmir, magic);
+    else
+	return drmAuthMagic(pNv->dev->fd, magic);
+}
+#endif
+
 Bool
 nouveau_dri2_init(ScreenPtr pScreen)
 {
@@ -804,6 +817,11 @@ nouveau_dri2_init(ScreenPtr pScreen)
 	dri2.GetParam = NULL;
 #endif
 
+#if DRI2INFOREC_VERSION >= 8 && defined(XMIR)
+	dri2.version = 8;
+	dri2.AuthMagic2 = nouveau_dri2_auth_magic;
+#endif
+
 #if DRI2INFOREC_VERSION >= 9
 	dri2.version = 9;
 	dri2.CreateBuffer2 = nouveau_dri2_create_buffer2;
diff --git a/src/nv_driver.c b/src/nv_driver.c
index b83b822..99bd735 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -226,6 +226,8 @@ NVDriverFunc(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data)
 	case GET_REQUIRED_HW_INTERFACES:
 	    flag = (CARD32 *)data;
 	    (*flag) = 0;
+	    if (xorgMir)
+		*flag |= HW_SKIP_CONSOLE;
 	    return TRUE;
 	default:
 	    return FALSE;
@@ -333,6 +335,23 @@ NVHasKMS(struct pci_device *pci_dev)
 }
 
 static Bool
+NVHasMirSupport(struct pci_device *pci_dev)
+{
+	char *busid;
+
+	busid = XNFprintf("pci:%04x:%02x:%02x.%d",
+			  pci_dev->domain, pci_dev->bus, pci_dev->dev, pci_dev->func);
+
+	if (xmir_get_drm_fd(busid) < 0) {
+		xf86DrvMsg(-1, X_ERROR, "[XMir] GPU %s not handled by Mir\n", busid);
+		free(busid);
+		return FALSE;
+	}
+	free(busid);
+	return TRUE;
+}
+
+static Bool
 NVPciProbe(DriverPtr drv, int entity_num, struct pci_device *pci_dev,
 	   intptr_t match_data)
 {
@@ -343,6 +362,9 @@ NVPciProbe(DriverPtr drv, int entity_num, struct pci_device *pci_dev,
 	};
 	ScrnInfoPtr pScrn = NULL;
 
+	if (xorgMir && !NVHasMirSupport(pci_dev))
+		return FALSE;
+
 	if (!NVHasKMS(pci_dev))
 		return FALSE;
 
@@ -367,6 +389,9 @@ NVPlatformProbe(DriverPtr driver,
 	if (!dev->pdev)
 		return FALSE;
 
+	if (xorgMir && !NVHasMirSupport(dev->pdev))
+		return FALSE;
+
 	if (!NVHasKMS(dev->pdev))
 		return FALSE;
 
@@ -424,9 +449,11 @@ NVEnterVT(VT_FUNC_ARGS_DECL)
 
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NVEnterVT is called.\n");
 
-	ret = drmSetMaster(pNv->dev->fd);
-	if (ret)
-		ErrorF("Unable to get master: %s\n", strerror(errno));
+	if (!xorgMir) {
+		ret = drmSetMaster(pNv->dev->fd);
+		if (ret)
+			ErrorF("Unable to get master: %s\n", strerror(errno));
+	}
 
 	if (XF86_CRTC_CONFIG_PTR(pScrn)->num_crtc && !xf86SetDesiredModes(pScrn))
 		return FALSE;
@@ -452,6 +479,9 @@ NVLeaveVT(VT_FUNC_ARGS_DECL)
 
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NVLeaveVT is called.\n");
 
+	if (xorgMir)
+		return;
+
 	ret = drmDropMaster(pNv->dev->fd);
 	if (ret && errno != EIO && errno != ENODEV)
 		ErrorF("Error dropping master: %i(%m)\n", -errno);
@@ -501,6 +531,88 @@ nouveau_dirty_update(ScreenPtr screen)
 }
 #endif
 
+#ifdef XMIR
+static void
+nouveau_xmir_copy_pixmap_to_mir(PixmapPtr src, int fd)
+{
+	ScreenPtr pScreen = src->drawable.pScreen;
+	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+	NVPtr pNv = NVPTR(pScrn);
+	ExaDriverPtr exa = pNv->EXADriverPtr;
+
+	PixmapPtr dst = NULL;
+	int ret;
+	struct nouveau_bo *bo_dst = NULL;
+
+	ret = nouveau_bo_prime_handle_ref(pNv->dev, fd, &bo_dst);
+	ErrorF("ret = %i for buffer %i\n", ret, fd);
+	assert(!ret);
+
+	dst = pScreen->CreatePixmap(pScreen, 0, 0, pScrn->depth, 0);
+	if (dst == NullPixmap)
+		goto cleanup_bo;
+
+	pScreen->ModifyPixmapHeader(dst, pScrn->virtualX, pScrn->virtualY, pScrn->depth, pScrn->depth,
+				    pScrn->virtualX, NULL);
+	nouveau_bo_ref(bo_dst, &nouveau_pixmap(dst)->bo);
+
+	ret = exa->PrepareCopy (src, dst, 0, 0, GXcopy, FB_ALLONES);
+	if (ret) {
+		exa->Copy (dst, 0, 0, 0, 0, pScrn->virtualX, pScrn->virtualY);
+		exa->DoneCopy (dst);
+		PUSH_KICK(pNv->pushbuf);
+	}
+
+cleanup_bo:
+	nouveau_bo_ref(NULL, &bo_dst);
+}
+
+static void
+nouveau_xmir_buffer_available(WindowPtr win)
+{
+    int fd;
+    PixmapPtr window_pixmap;
+    ScreenPtr screen = win->drawable.pScreen;
+
+    if (!xmir_window_is_dirty(win))
+        return;
+
+    fd = xmir_prime_fd_for_window(win);
+
+    window_pixmap = (*win->drawable.pScreen->GetWindowPixmap)(win);
+
+    assert(window_pixmap == screen->GetScreenPixmap(screen));
+
+    nouveau_xmir_copy_pixmap_to_mir(window_pixmap, fd);
+
+    xmir_submit_rendering_for_window(win, NULL);
+}
+
+static void
+nouveau_submit_dirty_window(WindowPtr win, DamagePtr damage)
+{
+	PixmapPtr window_pixmap;
+	int fd;
+
+	if (!xmir_window_has_free_buffer(win))
+		return;
+
+	fd = xmir_prime_fd_for_window(win);
+
+	window_pixmap = (*win->drawable.pScreen->GetWindowPixmap)(win);
+	nouveau_xmir_copy_pixmap_to_mir(window_pixmap, fd);
+
+	xmir_submit_rendering_for_window(win, DamageRegion(damage));
+
+	DamageEmpty(damage);
+}
+
+static xmir_driver xmir_nouveau_driver = {
+    XMIR_DRIVER_VERSION,
+    nouveau_xmir_buffer_available
+};
+#endif
+
 static void 
 NVBlockHandler (BLOCKHANDLER_ARGS_DECL)
 {
@@ -516,6 +628,11 @@ NVBlockHandler (BLOCKHANDLER_ARGS_DECL)
 	nouveau_dirty_update(pScreen);
 #endif
 
+#ifdef XMIR
+	if (pNv->xmir)
+		xmir_screen_for_each_damaged_window(pNv->xmir, nouveau_submit_dirty_window);
+#endif
+
 	if (pScrn->vtSema && !pNv->NoAccel)
 		nouveau_pushbuf_kick(pNv->pushbuf, pNv->pushbuf->channel);
 
@@ -535,7 +652,10 @@ NVCreateScreenResources(ScreenPtr pScreen)
 		return FALSE;
 	pScreen->CreateScreenResources = NVCreateScreenResources;
 
-	drmmode_fbcon_copy(pScreen);
+	if (!xorgMir)
+		drmmode_fbcon_copy(pScreen);
+	else if (!xf86SetDesiredModes(pScrn))
+		return FALSE;
 	if (!NVEnterVT(VT_FUNC_ARGS(0)))
 		return FALSE;
 
@@ -561,7 +681,7 @@ NVCloseScreen(CLOSE_SCREEN_ARGS_DECL)
 	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
 	NVPtr pNv = NVPTR(pScrn);
 
-	if (XF86_CRTC_CONFIG_PTR(pScrn)->num_crtc)
+	if (!xorgMir && XF86_CRTC_CONFIG_PTR(pScrn)->num_crtc)
 		drmmode_screen_fini(pScreen);
 
 	if (!pNv->NoAccel)
@@ -688,7 +808,7 @@ static Bool NVOpenDRMMaster(ScrnInfoPtr pScrn)
 	NVPtr pNv = NVPTR(pScrn);
 	NVEntPtr pNVEnt = NVEntPriv(pScrn);
 	struct pci_device *dev = pNv->PciInfo;
-	char *busid;
+	char *busid = NULL;
 	drmSetVersion sv;
 	int err;
 	int ret;
@@ -712,8 +832,11 @@ static Bool NVOpenDRMMaster(ScrnInfoPtr pScrn)
 	busid = XNFprintf("pci:%04x:%02x:%02x.%d",
 			  dev->domain, dev->bus, dev->dev, dev->func);
 #endif
+	if (!xorgMir)
+		ret = nouveau_device_open(busid, &pNv->dev);
+	else
+		ret = nouveau_device_wrap(xmir_get_drm_fd(busid), 0, &pNv->dev);
 
-	ret = nouveau_device_open(busid, &pNv->dev);
 	if (ret) {
 		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
 			   "[drm] Failed to open DRM device for %s: %d\n",
@@ -723,6 +846,9 @@ static Bool NVOpenDRMMaster(ScrnInfoPtr pScrn)
 	}
 	free(busid);
 
+	if (xorgMir)
+		return TRUE;
+
 	sv.drm_di_major = 1;
 	sv.drm_di_minor = 1;
 	sv.drm_dd_major = -1;
@@ -818,6 +944,14 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
 		)
 		return FALSE;
 
+#ifdef XMIR
+	if (xorgMir) {
+		pNv->xmir = xmir_screen_create(pScrn);
+		if (pNv->xmir == NULL)
+			NVPreInitFail("Mir failed to initialize\n");
+	}
+#endif
+
 	if (xf86IsEntityShared(pScrn->entityList[0])) {
 		if(!xf86IsPrimInitDone(pScrn->entityList[0])) {
 			pNv->Primary = TRUE;
@@ -965,6 +1099,8 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
 		from = X_CONFIG;
 		pNv->HWCursor = FALSE;
 	}
+	if (xorgMir)
+		pNv->HWCursor = FALSE;
 	xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
 		pNv->HWCursor ? "HW" : "SW");
 
@@ -1060,7 +1196,11 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
 	xf86DrvMsg(pScrn->scrnIndex, from, "Swap limit set to %d [Max allowed %d]%s\n",
 		   pNv->swap_limit, pNv->max_swap_limit, reason);
 
-	ret = drmmode_pre_init(pScrn, pNv->dev->fd, pScrn->bitsPerPixel >> 3);
+	if (xorgMir) {
+		xmir_screen_pre_init(pScrn, pNv->xmir, &xmir_nouveau_driver);
+		ret = TRUE;
+	} else
+		ret = drmmode_pre_init(pScrn, pNv->dev->fd, pScrn->bitsPerPixel >> 3);
 	if (ret == FALSE)
 		NVPreInitFail("Kernel modesetting failed to initialize\n");
 
@@ -1168,7 +1308,8 @@ NVUnmapMem(ScrnInfoPtr pScrn)
 {
 	NVPtr pNv = NVPTR(pScrn);
 
-	drmmode_remove_fb(pScrn);
+	if (!xorgMir)
+		drmmode_remove_fb(pScrn);
 
 	nouveau_bo_ref(NULL, &pNv->transfer);
 	nouveau_bo_ref(NULL, &pNv->scanout);
@@ -1368,6 +1509,11 @@ NVScreenInit(SCREEN_INIT_ARGS_DECL)
 	else
 		fbPictureInit (pScreen, 0, 0);
 
+#ifdef XMIR
+	if (pNv->xmir)
+		xmir_screen_init(pScreen, pNv->xmir);
+#endif
+
 	xf86SetBlackWhitePixels(pScreen);
 
 	if (!pNv->NoAccel && !nouveau_exa_init(pScreen))
@@ -1441,19 +1587,19 @@ NVScreenInit(SCREEN_INIT_ARGS_DECL)
 	 * Initialize colormap layer.
 	 * Must follow initialization of the default colormap 
 	 */
-	if (xf86_config->num_crtc &&
+	if (!xorgMir && xf86_config->num_crtc &&
 	    !xf86HandleColormaps(pScreen, 256, 8, NVLoadPalette,
 				 NULL, CMAP_PALETTED_TRUECOLOR))
-		return FALSE;
 
 	/* Report any unused options (only for the first generation) */
 	if (serverGeneration == 1)
 		xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
 
-	if (xf86_config->num_crtc)
+	if (!xorgMir && xf86_config->num_crtc)
 		drmmode_screen_init(pScreen);
 	else
 		pNv->glx_vblank = FALSE;
+
 	return TRUE;
 }
 
diff --git a/src/nv_type.h b/src/nv_type.h
index e6945bc..f844fff 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -9,6 +9,14 @@
 #include <stdint.h>
 #include "xf86Crtc.h"
 
+#ifdef XMIR
+#include "xmir.h"
+#include "xf86Priv.h"
+#else
+typedef struct xmir_screen xmir_screen;
+#define xorgMir 0
+#endif
+
 #if XF86_CRTC_VERSION >= 5
 #define NOUVEAU_PIXMAP_SHARING 1
 #endif
@@ -112,6 +120,8 @@ typedef struct _NVRec {
 	PixmapPtr pspix, pmpix, pdpix;
 	PicturePtr pspict, pmpict;
 	Pixel fg_colour;
+
+	xmir_screen *xmir;
 } NVRec;
 
 #define NVPTR(p) ((NVPtr)((p)->driverPrivate))
-- 
1.8.3.2



More information about the Nouveau mailing list