[Nouveau] [PATCH 1/5] nv50: implement wfb

Maarten Maathuis madman2003 at gmail.com
Sun Mar 8 07:31:50 PDT 2009


- Only for sufficiently new xserver's and exa_driver_pixmaps.
---
 src/nouveau_exa.c |  217 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/nv_driver.c   |   51 +++++++++++--
 src/nv_proto.h    |    4 +
 src/nv_type.h     |   12 +++-
 4 files changed, 267 insertions(+), 17 deletions(-)

diff --git a/src/nouveau_exa.c b/src/nouveau_exa.c
index 93fc3c5..074a226 100644
--- a/src/nouveau_exa.c
+++ b/src/nouveau_exa.c
@@ -259,7 +259,11 @@ nouveau_exa_mark_sync(ScreenPtr pScreen)
 static void
 nouveau_exa_wait_marker(ScreenPtr pScreen, int marker)
 {
-	NVSync(xf86Screens[pScreen->myNum]);
+	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+	NVPtr pNv = NVPTR(pScrn);
+
+	if (!pNv->exa_driver_pixmaps)
+		NVSync(xf86Screens[pScreen->myNum]);
 }
 
 static Bool
@@ -351,17 +355,16 @@ nouveau_exa_modify_pixmap_header(PixmapPtr ppix, int width, int height,
 
 	if (!nvpix->bo && nvpix->size) {
 		uint32_t cpp = ppix->drawable.bitsPerPixel >> 3;
-		/* At some point we should just keep 1bpp pixmaps in sysram */
 		uint32_t flags = NOUVEAU_BO_VRAM;
 		int ret;
 
 		if (pNv->Architecture >= NV_ARCH_50 && cpp) {
-			uint32_t aw = (width + 7) & ~7;
-			uint32_t ah = (height + 7) & ~7;
+			uint32_t ah = (height + 3) & ~3;
 
 			flags |= NOUVEAU_BO_TILED;
 
-			devkind = ((aw * cpp) + 63) & ~63;
+			/* This allignment is very important. */
+			devkind = (width * cpp + 63) & ~63;
 			nvpix->size = devkind * ah;
 		}
 
@@ -390,8 +393,11 @@ nouveau_exa_pixmap_is_tiled(PixmapPtr ppix)
 	NVPtr pNv = NVPTR(pScrn);
 
 	if (pNv->exa_driver_pixmaps) {
-		if (!nouveau_pixmap_bo(ppix)->tiled)
+		if (!nouveau_pixmap_bo(ppix))
+			return false;
+		if (nouveau_pixmap_bo(ppix)->tiled == 0)
 			return false;
+		return true;
 	} else
 	if (pNv->Architecture < NV_ARCH_50 ||
 	    exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase)
@@ -403,10 +409,12 @@ nouveau_exa_pixmap_is_tiled(PixmapPtr ppix)
 static void *
 nouveau_exa_pixmap_map(PixmapPtr ppix)
 {
+	ScrnInfoPtr pScrn = xf86Screens[ppix->drawable.pScreen->myNum];
+	NVPtr pNv = NVPTR(pScrn);
 	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
 	unsigned delta = nouveau_pixmap_offset(ppix);
 
-	if (bo->tiled) {
+	if (!pNv->wfb_enabled && bo->tiled) {
 		struct nouveau_pixmap *nvpix = nouveau_pixmap(ppix);
 
 		nvpix->linear = xcalloc(1, ppix->devKind * ppix->drawable.height);
@@ -426,9 +434,11 @@ nouveau_exa_pixmap_map(PixmapPtr ppix)
 static void
 nouveau_exa_pixmap_unmap(PixmapPtr ppix)
 {
+	ScrnInfoPtr pScrn = xf86Screens[ppix->drawable.pScreen->myNum];
+	NVPtr pNv = NVPTR(pScrn);
 	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
 
-	if (bo->tiled) {
+	if (!pNv->wfb_enabled && bo->tiled) {
 		struct nouveau_pixmap *nvpix = nouveau_pixmap(ppix);
 
 		NVAccelUploadM2MF(ppix, 0, 0, ppix->drawable.width,
@@ -674,3 +684,194 @@ nouveau_exa_init(ScreenPtr pScreen)
 	pNv->EXADriverPtr = exa;
 	return TRUE;
 }
+
+/* WFB functions. */
+
+static FbBits
+nouveau_exa_wfb_read_memory_linear(const void *src, int size)
+{
+	FbBits bits = 0;
+
+	memcpy(&bits, src, size);
+
+	return bits;
+}
+
+static void
+nouveau_exa_wfb_write_memory_linear(void *dst, FbBits value, int size)
+{
+	memcpy(dst, &value, size);
+}
+
+#define TILE_PITCH 32
+#define TILE_HEIGHT 4
+#define SUBTILE_PITCH 8
+#define SUBTILE_HEIGHT 2
+
+#define LINEAR_PITCH (pPixmap->devKind)
+#define NUM_TILES_WIDTH (LINEAR_PITCH/TILE_PITCH)
+
+static NVPtr last_wfb_pNv = NULL;
+
+/* Note, we can only expose one read and write function, the linear versions are for internal consumption. */
+static FbBits
+nouveau_exa_wfb_read_memory(const void *src, int size)
+{
+	int i, line_x, line_y, tile_x, tile_y, subtile_x, subtile_y;
+	unsigned long offset = (unsigned long) src, subpixel_offset;
+	PixmapPtr pPixmap = NULL;
+	FbBits bits = 0;
+	void *new_src;
+
+	if (!last_wfb_pNv)
+		return nouveau_exa_wfb_read_memory_linear(src, size);
+
+	/* Find the right pixmap. */
+	for (i = 0; i < 6; i++)
+		if (offset >= last_wfb_pNv->wfb_pixmaps[i].start && offset < last_wfb_pNv->wfb_pixmaps[i].end) {
+			pPixmap = last_wfb_pNv->wfb_pixmaps[i].ppix;
+			break;
+		}
+
+	if (!pPixmap || !last_wfb_pNv->wfb_pixmaps[i].tiled)
+		return nouveau_exa_wfb_read_memory_linear(src, size);
+
+	/* Now comes the decoding. */
+	offset -= (unsigned long) pPixmap->devPrivate.ptr;
+	/* Assuming dword alligned offsets. */
+	subpixel_offset = offset & ((pPixmap->drawable.bitsPerPixel >> 3) - 1);
+	offset &= ~((pPixmap->drawable.bitsPerPixel >> 3) - 1);
+
+	/* Determine the coordinate first. */
+	line_y = offset/LINEAR_PITCH;
+	line_x = offset - line_y * LINEAR_PITCH;
+	tile_x = line_x/TILE_PITCH;
+	tile_y = line_y/TILE_HEIGHT;
+	subtile_x = (line_x - tile_x * TILE_PITCH)/SUBTILE_PITCH;
+	subtile_y = (line_y - tile_y * TILE_HEIGHT)/SUBTILE_HEIGHT;
+
+	new_src = pPixmap->devPrivate.ptr +
+		(((tile_y * NUM_TILES_WIDTH) + tile_x) * (TILE_HEIGHT * TILE_PITCH)) +
+		(((subtile_y * (TILE_PITCH/SUBTILE_PITCH)) + subtile_x) * (SUBTILE_HEIGHT * SUBTILE_PITCH)) +
+		((line_y - tile_y * TILE_HEIGHT - subtile_y * SUBTILE_HEIGHT) * SUBTILE_PITCH) + 
+		(line_x - tile_x * TILE_PITCH - subtile_x * SUBTILE_PITCH) +
+		subpixel_offset;
+
+	memcpy(&bits, new_src, size);
+
+	return bits;
+}
+
+static void
+nouveau_exa_wfb_write_memory(void *dst, FbBits value, int size)
+{
+	int i, line_x, line_y, tile_x, tile_y, subtile_x, subtile_y;
+	unsigned long offset = (unsigned long) dst, subpixel_offset;
+	PixmapPtr pPixmap = NULL;
+	void *new_dst;
+
+	if (!last_wfb_pNv) {
+		nouveau_exa_wfb_write_memory_linear(dst, value, size);
+		return;
+	}
+
+	/* Find the right pixmap. */
+	for (i = 0; i < 6; i++)
+		if (offset >= last_wfb_pNv->wfb_pixmaps[i].start && offset < last_wfb_pNv->wfb_pixmaps[i].end) {
+			pPixmap = last_wfb_pNv->wfb_pixmaps[i].ppix;
+			break;
+		}
+
+	if (!pPixmap || !last_wfb_pNv->wfb_pixmaps[i].tiled) {
+		nouveau_exa_wfb_write_memory_linear(dst, value, size);
+		return;
+	}
+
+	/* Now comes the decoding. */
+	offset -= (unsigned long) pPixmap->devPrivate.ptr;
+	/* Assuming dword alligned offsets. */
+	subpixel_offset = offset & ((pPixmap->drawable.bitsPerPixel >> 3) - 1);
+	offset &= ~((pPixmap->drawable.bitsPerPixel >> 3) - 1);
+
+	/* Determine the coordinate first. */
+	line_y = offset/LINEAR_PITCH;
+	line_x = offset - line_y * LINEAR_PITCH;
+	tile_x = line_x/TILE_PITCH;
+	tile_y = line_y/TILE_HEIGHT;
+	subtile_x = (line_x - tile_x * TILE_PITCH)/SUBTILE_PITCH;
+	subtile_y = (line_y - tile_y * TILE_HEIGHT)/SUBTILE_HEIGHT;
+
+	new_dst = pPixmap->devPrivate.ptr +
+		(((tile_y * NUM_TILES_WIDTH) + tile_x) * (TILE_HEIGHT * TILE_PITCH)) +
+		(((subtile_y * (TILE_PITCH/SUBTILE_PITCH)) + subtile_x) * (SUBTILE_HEIGHT * SUBTILE_PITCH)) +
+		((line_y - tile_y * TILE_HEIGHT - subtile_y * SUBTILE_HEIGHT) * SUBTILE_PITCH) + 
+		(line_x - tile_x * TILE_PITCH - subtile_x * SUBTILE_PITCH) +
+		subpixel_offset;
+
+	memcpy(new_dst, &value, size);
+}
+
+void
+nouveau_exa_wfb_setup_wrap(ReadMemoryProcPtr *pRead,
+				WriteMemoryProcPtr *pWrite,
+				DrawablePtr pDraw)
+{
+	ScrnInfoPtr pScrn = xf86Screens[pDraw->pScreen->myNum];
+	NVPtr pNv = NVPTR(pScrn);
+	PixmapPtr pPixmap;
+
+	if (!pRead || !pWrite)
+		return;
+
+	pPixmap = NVGetDrawablePixmap(pDraw);
+	if (!pPixmap)
+		return;
+
+	int i;
+	for (i = 0; i < 6; i++)
+		if (!pNv->wfb_pixmaps[i].used)
+			break;
+
+	if (i == 6) {
+		ErrorF("More than 10 wraps are setup, what the hell is going on?\n");
+		*pRead = NULL;
+		*pWrite = NULL;
+		return;
+	}
+
+	/* We will get a pointer, somewhere in the range of this pixmap. */
+	/* Based on linear representation ofcource. */
+	pNv->wfb_pixmaps[i].ppix = pPixmap;
+	pNv->wfb_pixmaps[i].start = (unsigned long) pPixmap->devPrivate.ptr;
+	pNv->wfb_pixmaps[i].end = pNv->wfb_pixmaps[i].start + exaGetPixmapPitch(pPixmap) * ((pPixmap->drawable.height + 3) & ~3);
+	pNv->wfb_pixmaps[i].used = true;
+	pNv->wfb_pixmaps[i].tiled = nouveau_exa_pixmap_is_tiled(pPixmap);
+
+	*pRead = nouveau_exa_wfb_read_memory;
+	*pWrite = nouveau_exa_wfb_write_memory;
+
+	last_wfb_pNv = pNv;
+}
+
+void
+nouveau_exa_wfb_finish_wrap(DrawablePtr pDraw)
+{
+	ScrnInfoPtr pScrn = xf86Screens[pDraw->pScreen->myNum];
+	NVPtr pNv = NVPTR(pScrn);
+	PixmapPtr pPixmap;
+	int i;
+
+	pPixmap = NVGetDrawablePixmap(pDraw);
+	if (!pPixmap)
+		return;
+
+	for (i = 0; i < 6; i++)
+		if (pNv->wfb_pixmaps[i].ppix == pPixmap) {
+			pNv->wfb_pixmaps[i].ppix = NULL;
+			pNv->wfb_pixmaps[i].start = 0;
+			pNv->wfb_pixmaps[i].end = 0;
+			pNv->wfb_pixmaps[i].used = false;
+			pNv->wfb_pixmaps[i].tiled = false;
+			break;
+		}
+}
diff --git a/src/nv_driver.c b/src/nv_driver.c
index d7e8025..4c6b691 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -157,6 +157,12 @@ static const char *fbSymbols[] = {
     NULL
 };
 
+static const char *wfbSymbols[] = {
+    "wfbPictureInit",
+    "wfbScreenInit",
+    NULL
+};
+
 static const char *exaSymbols[] = {
     "exaDriverInit",
     "exaOffscreenInit",
@@ -285,7 +291,7 @@ nouveauSetup(pointer module, pointer opts, int *errmaj, int *errmin)
 		 * Tell the loader about symbols from other modules that this module
 		 * might refer to.
 		 */
-		LoaderRefSymLists(vgahwSymbols, exaSymbols, fbSymbols,
+		LoaderRefSymLists(vgahwSymbols, exaSymbols, fbSymbols, wfbSymbols,
 				ramdacSymbols, shadowSymbols, drmSymbols, 
 				i2cSymbols, ddcSymbols, vbeSymbols,
 				int10Symbols, NULL);
@@ -1510,10 +1516,22 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
 	 * section.
 	 */
 
-	if (xf86LoadSubModule(pScrn, "fb") == NULL)
-		NVPreInitFail("\n");
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0,0)
+	if (!pNv->NoAccel && pNv->exa_driver_pixmaps && pNv->Architecture == NV_ARCH_50) {
+		pNv->wfb_enabled = true;
+		if (xf86LoadSubModule(pScrn, "wfb") == NULL)
+			NVPreInitFail("\n");
 
-	xf86LoaderReqSymLists(fbSymbols, NULL);
+		xf86LoaderReqSymLists(wfbSymbols, NULL);
+	} else
+#endif
+	{
+		pNv->wfb_enabled = false;
+		if (xf86LoadSubModule(pScrn, "fb") == NULL)
+			NVPreInitFail("\n");
+
+		xf86LoaderReqSymLists(fbSymbols, NULL);
+	}
 
 	/* Load EXA if needed */
 	if (!pNv->NoAccel) {
@@ -2154,9 +2172,19 @@ NVScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
 	switch (pScrn->bitsPerPixel) {
 		case 16:
 		case 32:
-			ret = fbScreenInit(pScreen, FBStart, pScrn->virtualX, pScrn->virtualY,
-				pScrn->xDpi, pScrn->yDpi,
-				displayWidth, pScrn->bitsPerPixel);
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0,0)
+			if (pNv->wfb_enabled) {
+				ret = wfbScreenInit(pScreen, FBStart, pScrn->virtualX, pScrn->virtualY,
+					pScrn->xDpi, pScrn->yDpi,
+					displayWidth, pScrn->bitsPerPixel,
+					nouveau_exa_wfb_setup_wrap, nouveau_exa_wfb_finish_wrap);
+			} else
+#endif
+			{
+				ret = fbScreenInit(pScreen, FBStart, pScrn->virtualX, pScrn->virtualY,
+					pScrn->xDpi, pScrn->yDpi,
+					displayWidth, pScrn->bitsPerPixel);
+			}
 			break;
 		default:
 			xf86DrvMsg(scrnIndex, X_ERROR,
@@ -2181,7 +2209,14 @@ NVScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
 		}
 	}
 
-	fbPictureInit (pScreen, 0, 0);
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0,0)
+	if (pNv->wfb_enabled) {
+		wfbPictureInit(pScreen, 0, 0);
+	} else
+#endif
+	{
+		fbPictureInit(pScreen, 0, 0);
+	}
 
 	xf86SetBlackWhitePixels(pScreen);
 
diff --git a/src/nv_proto.h b/src/nv_proto.h
index 28605a8..5933ddd 100644
--- a/src/nv_proto.h
+++ b/src/nv_proto.h
@@ -65,6 +65,10 @@ void  NVTakedownDma(ScrnInfoPtr pScrn);
 Bool nouveau_exa_init(ScreenPtr pScreen);
 Bool nouveau_exa_pixmap_is_onscreen(PixmapPtr pPixmap);
 bool nouveau_exa_pixmap_is_tiled(PixmapPtr ppix);
+void nouveau_exa_wfb_setup_wrap(ReadMemoryProcPtr *pRead,
+				WriteMemoryProcPtr *pWrite,
+				DrawablePtr pDraw);
+void nouveau_exa_wfb_finish_wrap(DrawablePtr pDraw);
 
 /* in nv_hw.c */
 void NVCalcStateExt(ScrnInfoPtr,struct _riva_hw_state *,int,int,int,int,int,int);
diff --git a/src/nv_type.h b/src/nv_type.h
index 78a7802..bec4851 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -303,7 +303,8 @@ typedef struct _NVRec {
 
     uint8_t cur_head;
     ExaDriverPtr	EXADriverPtr;
-    Bool		exa_driver_pixmaps;
+    Bool exa_driver_pixmaps;
+    bool wfb_enabled;
     xf86CursorInfoPtr   CursorInfoRec;
     ScreenBlockHandlerProcPtr BlockHandler;
     CloseScreenProcPtr  CloseScreen;
@@ -404,6 +405,15 @@ typedef struct _NVRec {
 	unsigned point_x, point_y;
 	unsigned width_in, width_out;
 	unsigned height_in, height_out;
+
+	/* Wfb related data. */
+	struct {
+		PixmapPtr ppix;
+		bool used;
+		bool tiled;
+		unsigned long start;
+		unsigned long end;
+	} wfb_pixmaps[6];
 } NVRec;
 
 #define NVPTR(p) ((NVPtr)((p)->driverPrivate))
-- 
1.6.2



More information about the Nouveau mailing list