Maarten Maathuis
2009-Feb-12  22:56 UTC
[Nouveau] [PATCH 1/3] exa: add nouveau_exa_pixmap_is_tiled
---
 src/nouveau_exa.c |   19 +++++++++++++++----
 src/nv50_exa.c    |    6 +++---
 src/nv50_xv.c     |    5 +----
 src/nv_proto.h    |    1 +
 4 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/src/nouveau_exa.c b/src/nouveau_exa.c
index a947a31..3babfd7 100644
--- a/src/nouveau_exa.c
+++ b/src/nouveau_exa.c
@@ -52,8 +52,7 @@ NVAccelDownloadM2MF(PixmapPtr pspix, int x, int y, int w, int
h,
 	unsigned line_len = w * cpp;
 	unsigned src_pitch = 0, src_offset = 0, linear = 0;
 
-	if (pNv->Architecture < NV_ARCH_50 ||
-	    exaGetPixmapOffset(pspix) < pNv->EXADriverPtr->offScreenBase) {
+	if (!nouveau_exa_pixmap_is_tiled(pspix)) {
 		linear     = 1;
 		src_pitch  = exaGetPixmapPitch(pspix);
 		src_offset = (y * src_pitch) + (x * cpp);
@@ -162,8 +161,7 @@ NVAccelUploadM2MF(PixmapPtr pdpix, int x, int y, int w, int
h,
 	unsigned line_len = w * cpp;
 	unsigned dst_pitch = 0, dst_offset = 0, linear = 0;
 
-	if (pNv->Architecture < NV_ARCH_50 ||
-	    exaGetPixmapOffset(pdpix) < pNv->EXADriverPtr->offScreenBase) {
+	if (!nouveau_exa_pixmap_is_tiled(pdpix)) {
 		linear     = 1;
 		dst_pitch  = exaGetPixmapPitch(pdpix);
 		dst_offset = (y * dst_pitch) + (x * cpp);
@@ -275,6 +273,19 @@ nouveau_exa_wait_marker(ScreenPtr pScreen, int marker)
 	NVSync(xf86Screens[pScreen->myNum]);
 }
 
+bool
+nouveau_exa_pixmap_is_tiled(PixmapPtr ppix)
+{
+	ScrnInfoPtr pScrn = xf86Screens[ppix->drawable.pScreen->myNum];
+	NVPtr pNv = NVPTR(pScrn);
+
+	if (pNv->Architecture < NV_ARCH_50 ||
+		exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase)
+		return false;
+
+	return true;
+}
+
 static void *
 nouveau_exa_pixmap_map(PixmapPtr ppix)
 {
diff --git a/src/nv50_exa.c b/src/nv50_exa.c
index 9030d22..96c0aa3 100644
--- a/src/nv50_exa.c
+++ b/src/nv50_exa.c
@@ -117,7 +117,7 @@ NV50EXAAcquireSurface2D(PixmapPtr ppix, int is_src)
 	bo_flags  = NOUVEAU_BO_VRAM;
 	bo_flags |= is_src ? NOUVEAU_BO_RD : NOUVEAU_BO_WR;
 
-	if (exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase) {
+	if (!nouveau_exa_pixmap_is_tiled(ppix)) {
 		BEGIN_RING(chan, eng2d, mthd, 2);
 		OUT_RING  (chan, fmt);
 		OUT_RING  (chan, 1);
@@ -438,7 +438,7 @@ NV50EXARenderTarget(PixmapPtr ppix, PicturePtr ppict)
 	unsigned format;
 
 	/*XXX: Scanout buffer not tiled, someone needs to figure it out */
-	if (exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase)
+	if (!nouveau_exa_pixmap_is_tiled(ppix))
 		NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
 
 	switch (ppict->format) {
@@ -511,7 +511,7 @@ NV50EXATexture(PixmapPtr ppix, PicturePtr ppict, unsigned
unit)
 	const unsigned tcb_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM;
 
 	/*XXX: Scanout buffer not tiled, someone needs to figure it out */
-	if (exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase)
+	if (!nouveau_exa_pixmap_is_tiled(ppix))
 		NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
 
 	BEGIN_RING(chan, tesla, NV50TCL_TIC_ADDRESS_HIGH, 3);
diff --git a/src/nv50_xv.c b/src/nv50_xv.c
index 0e7d2c4..1ddfeee 100644
--- a/src/nv50_xv.c
+++ b/src/nv50_xv.c
@@ -39,9 +39,6 @@
 static Bool
 nv50_xv_check_image_put(PixmapPtr ppix)
 {
-	ScrnInfoPtr pScrn = xf86Screens[ppix->drawable.pScreen->myNum];
-	NVPtr pNv = NVPTR(pScrn);
-
 	switch (ppix->drawable.depth) {
 	case 32:
 	case 24:
@@ -51,7 +48,7 @@ nv50_xv_check_image_put(PixmapPtr ppix)
 		return FALSE;
 	}
 
-	if (exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase)
+	if (!nouveau_exa_pixmap_is_tiled(ppix))
 		return FALSE;
 
 	return TRUE;
diff --git a/src/nv_proto.h b/src/nv_proto.h
index 3cb54ef..cc0d2cc 100644
--- a/src/nv_proto.h
+++ b/src/nv_proto.h
@@ -64,6 +64,7 @@ void  NVTakedownDma(ScrnInfoPtr pScrn);
 /* in nouveau_exa.c */
 Bool nouveau_exa_init(ScreenPtr pScreen);
 Bool nouveau_exa_pixmap_is_onscreen(PixmapPtr pPixmap);
+bool nouveau_exa_pixmap_is_tiled(PixmapPtr ppix);
 
 /* in nv_hw.c */
 void NVCalcStateExt(ScrnInfoPtr,struct _riva_hw_state
*,int,int,int,int,int,int);
-- 
1.6.1.2
Maarten Maathuis
2009-Feb-12  22:56 UTC
[Nouveau] [PATCH 2/3] nv50: initial bits for "shadowfb"
- Fallbacks on the frontbuffer still need to be handled.
---
 src/Makefile.am          |    1 +
 src/nouveau_exa.c        |    7 +--
 src/nv50_randr.c         |    2 +-
 src/nv50_shadow_damage.c |  164 ++++++++++++++++++++++++++++++++++++++++++++++
 src/nv_driver.c          |   46 ++++++++++++--
 src/nv_proto.h           |    3 +
 src/nv_type.h            |    3 +
 7 files changed, 214 insertions(+), 12 deletions(-)
 create mode 100644 src/nv50_shadow_damage.c
diff --git a/src/Makefile.am b/src/Makefile.am
index f2ba849..4294796 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -79,6 +79,7 @@ nouveau_drv_la_SOURCES = \
 			 nv50_xv.c \
 			 nv50_texture.h \
 			 nv50reg.h \
+			 nv50_shadow_damage.c \
 			 nouveau_crtc.h \
 			 nouveau_output.h \
 			 nouveau_connector.h \
diff --git a/src/nouveau_exa.c b/src/nouveau_exa.c
index 3babfd7..c4cafb0 100644
--- a/src/nouveau_exa.c
+++ b/src/nouveau_exa.c
@@ -279,8 +279,7 @@ nouveau_exa_pixmap_is_tiled(PixmapPtr ppix)
 	ScrnInfoPtr pScrn = xf86Screens[ppix->drawable.pScreen->myNum];
 	NVPtr pNv = NVPTR(pScrn);
 
-	if (pNv->Architecture < NV_ARCH_50 ||
-		exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase)
+	if (pNv->Architecture < NV_ARCH_50)
 		return false;
 
 	return true;
@@ -437,10 +436,6 @@ nouveau_exa_init(ScreenPtr pScreen)
 	exa->memorySize = pNv->FB->size; 
 
 	if (pNv->Architecture >= NV_ARCH_50) {
-		nouveau_bo_tile(pNv->FB, NOUVEAU_BO_VRAM | NOUVEAU_BO_TILED,
-				exa->offScreenBase,
-				exa->memorySize - exa->offScreenBase);
-
 		exa->maxX = 8192;
 		exa->maxY = 8192;
 	} else
diff --git a/src/nv50_randr.c b/src/nv50_randr.c
index f1cca0c..fcf5d7f 100644
--- a/src/nv50_randr.c
+++ b/src/nv50_randr.c
@@ -99,7 +99,7 @@ nv50_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
DisplayModePtr adjuste
 		nv_crtc->crtc->SetFB(nv_crtc->crtc, nv_crtc->shadow);
 		nv_crtc->crtc->SetFBOffset(nv_crtc->crtc, 0, 0);
 	} else {
-		nv_crtc->crtc->SetFB(nv_crtc->crtc, pNv->FB);
+		nv_crtc->crtc->SetFB(nv_crtc->crtc, pNv->scanout);
 		nv_crtc->crtc->SetFBOffset(nv_crtc->crtc, x, y);
 	}
 	nv_crtc->crtc->ModeSet(nv_crtc->crtc, mode);
diff --git a/src/nv50_shadow_damage.c b/src/nv50_shadow_damage.c
new file mode 100644
index 0000000..9d1a8cb
--- /dev/null
+++ b/src/nv50_shadow_damage.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2009 Maarten Maathuis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
"Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * This file serves to process all damage to the frontbuffer pixmap.
+ * This is needed until we can/have:
+ * - Tiled frontbufffer support.
+ * - Working wfb support.
+ * - Widespread wfb exa support.
+ */
+
+#include "nv_include.h"
+
+/* When driver allocated pixmaps are used we can easily fold this back into exa
code. */
+static void nv50_shadow_damage_blit(PixmapPtr ppix, RegionPtr pRegion)
+{
+	ScrnInfoPtr pScrn = xf86Screens[ppix->drawable.pScreen->myNum];
+	NVPtr pNv = NVPTR(pScrn);
+	struct nouveau_channel *chan = pNv->chan;
+	struct nouveau_grobj *eng2d = pNv->Nv2D;
+	uint32_t fmt;
+	BoxPtr pbox;
+	int nbox;
+
+	pbox = REGION_RECTS(pRegion);
+	nbox = REGION_NUM_RECTS(pRegion);
+	if (!nbox)
+		return;
+
+	/* flush_notify is not needed, we check for all the ring space in advance. */
+	WAIT_RING (chan, 26 + nbox * 13);
+
+	switch (ppix->drawable.depth) {
+		case 8 : fmt = NV50_2D_SRC_FORMAT_8BPP; break;
+		case 15: fmt = NV50_2D_SRC_FORMAT_15BPP; break;
+		case 16: fmt = NV50_2D_SRC_FORMAT_16BPP; break;
+		case 24: fmt = NV50_2D_SRC_FORMAT_24BPP; break;
+		case 32: fmt = NV50_2D_SRC_FORMAT_32BPP; break;
+		default:
+			 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+				    "Unknown surface format for bpp=%d\n",
+				    ppix->drawable.depth);
+			 return;
+	}
+
+	/* tiled source */
+	BEGIN_RING(chan, eng2d, NV50_2D_SRC_FORMAT, 5);
+	OUT_RING  (chan, fmt);
+	OUT_RING  (chan, 0);
+	OUT_RING  (chan, 0);
+	OUT_RING  (chan, 1);
+	OUT_RING  (chan, 0);
+
+	BEGIN_RING(chan, eng2d, NV50_2D_SRC_WIDTH, 4);
+	OUT_RING  (chan, ppix->drawable.width);
+	OUT_RING  (chan, ppix->drawable.height);
+	OUT_PIXMAPh(chan, ppix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+	OUT_PIXMAPl(chan, ppix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+
+	/* untiled destination */
+	BEGIN_RING(chan, eng2d, NV50_2D_DST_FORMAT, 2);
+	OUT_RING  (chan, fmt);
+	OUT_RING  (chan, 1);
+	BEGIN_RING(chan, eng2d, NV50_2D_DST_PITCH, 5);
+	OUT_RING  (chan, NOUVEAU_ALIGN(pScrn->virtualX, 64) *
+			 (pScrn->bitsPerPixel >> 3));
+	OUT_RING  (chan, ppix->drawable.width);
+	OUT_RING  (chan, ppix->drawable.height);
+	OUT_RELOCh(chan, pNv->scanout, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+	OUT_RELOCl(chan, pNv->scanout, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+
+	BEGIN_RING(chan, eng2d, NV50_2D_CLIP_X, 4);
+	OUT_RING  (chan, 0);
+	OUT_RING  (chan, 0);
+	OUT_RING  (chan, ppix->drawable.width);
+	OUT_RING  (chan, ppix->drawable.height);
+	BEGIN_RING(chan, eng2d, NV50_2D_OPERATION, 1);
+	OUT_RING  (chan, NV50_2D_OPERATION_SRCCOPY);
+
+	while (nbox--) {
+		BEGIN_RING(chan, eng2d, NV50_2D_BLIT_DST_X, 12);
+		OUT_RING  (chan, pbox->x1);
+		OUT_RING  (chan, pbox->y1);
+		OUT_RING  (chan, pbox->x2 - pbox->x1);
+		OUT_RING  (chan, pbox->y2 - pbox->y1);
+		OUT_RING  (chan, 0);
+		OUT_RING  (chan, 1);
+		OUT_RING  (chan, 0);
+		OUT_RING  (chan, 1);
+		OUT_RING  (chan, 0);
+		OUT_RING  (chan, pbox->x1);
+		OUT_RING  (chan, 0);
+		OUT_RING  (chan, pbox->y1);
+
+		pbox++;
+	}
+}
+
+static void nv50_shadow_damage_report(DamagePtr pDamage, RegionPtr pRegion,
void *closure)
+{
+	PixmapPtr ppix = closure;
+
+	nv50_shadow_damage_blit(ppix, pRegion);
+}
+
+static void nv50_shadow_damage_destroy(DamagePtr pDamage, void *closure)
+{
+	PixmapPtr ppix = closure;
+	ScrnInfoPtr pScrn = xf86Screens[ppix->drawable.pScreen->myNum];
+	NVPtr pNv = NVPTR(pScrn);
+
+	pNv->screen_damage = NULL;
+}
+
+bool nv50_shadow_damage_create(ScrnInfoPtr pScrn)
+{
+	NVPtr pNv = NVPTR(pScrn);
+	ScreenPtr pScreen = pScrn->pScreen;
+	PixmapPtr ppix = NULL;
+
+	if (pNv->Architecture < NV_ARCH_50)
+		return false;
+
+	ppix = pScreen->GetScreenPixmap(pScreen);
+	if (!ppix) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			"No screen pixmap.\n");
+		return false;
+	}
+
+	pNv->screen_damage = DamageCreate(nv50_shadow_damage_report,
nv50_shadow_damage_destroy,
+		DamageReportRawRegion, true, pScreen, ppix);
+	if (!pNv->screen_damage) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			"No screen damage\n");
+		return false;
+	}
+
+	/* We want the notification after submission. */
+	DamageSetReportAfterOp(pNv->screen_damage, true);
+
+	DamageRegister(&ppix->drawable, pNv->screen_damage);
+
+	return true;
+}
diff --git a/src/nv_driver.c b/src/nv_driver.c
index 3d6e9ea..c302412 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -1580,6 +1580,8 @@ NVMapMemSW(ScrnInfoPtr pScrn)
 		return FALSE;
 	pNv->GART = NULL;
 
+	nouveau_bo_ref(pNv->FB, &pNv->scanout);
+
 	ret = nouveau_bo_fake(&dev, Cursor0Offset,
 			      NOUVEAU_BO_VRAM | NOUVEAU_BO_PIN,
 			      64*1024, pNv->VRAMMap + Cursor0Offset,
@@ -1625,6 +1627,7 @@ NVMapMem(ScrnInfoPtr pScrn)
 	NVPtr pNv = NVPTR(pScrn);
 	int gart_scratch_size;
 	uint64_t res;
+	uint32_t flags;
 
 	if (pNv->NoAccel)
 		return NVMapMemSW(pScrn);
@@ -1636,15 +1639,39 @@ NVMapMem(ScrnInfoPtr pScrn)
 	nouveau_device_get_param(pNv->dev, NOUVEAU_GETPARAM_AGP_SIZE, &res);
 	pNv->AGPSize=res;
 
-	if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM | NOUVEAU_BO_PIN,
-		0, pNv->VRAMPhysicalSize / 2, &pNv->FB)) {
-			xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate memory for
framebuffer!\n");
-			return FALSE;
-	}
+	flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_PIN;
+	if (pNv->Architecture >= NV_ARCH_50)
+		flags |= NOUVEAU_BO_TILED;
+
+	if (nouveau_bo_new(pNv->dev, flags, 0, pNv->VRAMPhysicalSize / 2,
+			   &pNv->FB)) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			   "Failed to allocate memory for framebuffer!\n");
+		return FALSE;
+ 	}
+
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		"Allocated %dMiB VRAM for framebuffer + offscreen pixmaps, at offset
0x%X\n",
 		(uint32_t)(pNv->FB->size >> 20), (uint32_t)
pNv->FB->offset);
 
+	/* Allocate linear scanout. */
+	if (pNv->Architecture >= NV_ARCH_50) {
+		unsigned scanout_size;
+
+		scanout_size = NOUVEAU_ALIGN(pScrn->virtualX, 64);
+		scanout_size *= (pScrn->bitsPerPixel >> 3);
+		scanout_size *= pScrn->virtualY;
+
+		if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM | NOUVEAU_BO_PIN,
+				   0, scanout_size, &pNv->scanout)) {
+			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+				   "Failed to allocate scanout buffer\n");
+			return FALSE;
+		}
+	} else {
+		nouveau_bo_ref(pNv->FB, &pNv->scanout);
+	}
+
 	if (pNv->AGPSize) {
 		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 			   "AGPGART: %dMiB available\n",
@@ -1743,6 +1770,7 @@ NVUnmapMem(ScrnInfoPtr pScrn)
 	}
 
 	nouveau_bo_ref(NULL, &pNv->FB);
+	nouveau_bo_ref(NULL, &pNv->scanout);
 	nouveau_bo_ref(NULL, &pNv->GART);
 	nouveau_bo_ref(NULL, &pNv->Cursor);
 	nouveau_bo_ref(NULL, &pNv->Cursor2);
@@ -2268,6 +2296,14 @@ NVSaveScreen(ScreenPtr pScreen, int mode)
 	bool on = xf86IsUnblank(mode);
 	int i;
 
+	/* This might seem strange, but we need an entry point after
CreateScreenResources.
+	 * This happens to one of the few, if not the only place.
+	 * When we move to driver allocated pixmaps, we can move this.
+	 */
+	if (mode == SCREEN_SAVER_FORCER && pNv->Architecture == NV_ARCH_50
&&
+		!pNv->screen_damage && !nv50_shadow_damage_create(pScrn))
+		return FALSE;
+
 	if (!pNv->randr12_enable)
 		return vgaHWSaveScreen(pScreen, mode);
 
diff --git a/src/nv_proto.h b/src/nv_proto.h
index cc0d2cc..f39c294 100644
--- a/src/nv_proto.h
+++ b/src/nv_proto.h
@@ -276,6 +276,9 @@ void nv50_xv_video_stop(ScrnInfoPtr, pointer, Bool);
 int nv50_xv_port_attribute_set(ScrnInfoPtr, Atom, INT32, pointer);
 int nv50_xv_port_attribute_get(ScrnInfoPtr, Atom, INT32 *, pointer);
 
+/* nv50_shadow_damage.c */
+bool nv50_shadow_damage_create(ScrnInfoPtr pScrn);
+
 /* To support EXA 2.0, 2.1 has this in the header */
 #ifndef exaMoveInPixmap
 extern void exaMoveInPixmap(PixmapPtr pPixmap);
diff --git a/src/nv_type.h b/src/nv_type.h
index 6da8561..cd9a45c 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -248,12 +248,15 @@ typedef struct _NVRec {
 
     /* Various pinned memory regions */
     struct nouveau_bo * FB;
+    struct nouveau_bo * scanout;
     //struct nouveau_bo * FB_old; /* for KMS */
     struct nouveau_bo * shadow[2]; /* for easy acces by exa */
     struct nouveau_bo * Cursor;
     struct nouveau_bo * Cursor2;
     struct nouveau_bo * GART;
 
+    DamagePtr screen_damage; /* for NV50+ */
+
     struct nouveau_bios	VBIOS;
     Bool                NoAccel;
     Bool                HWCursor;
-- 
1.6.1.2