[Intel-gfx] [PATCH] Reallocate frame buffer on resize

Keith Packard keithp at keithp.com
Fri Dec 12 00:30:39 CET 2008


When running UXA (and not DRI1), we can resize the frame buffer.
Signed-off-by: Keith Packard <keithp at keithp.com>
---
 src/i830.h         |    9 +++
 src/i830_display.c |   29 ++++++++++-
 src/i830_display.h |    1 +
 src/i830_driver.c  |  143 ++++++++++++++++++++++++++++++++++++++-------------
 src/i830_exa.c     |   22 ++++++++
 src/i830_memory.c  |   17 ++++--
 6 files changed, 178 insertions(+), 43 deletions(-)

diff --git a/src/i830.h b/src/i830.h
index 8ad5c69..2ab8893 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -95,6 +95,7 @@ void i830_uxa_block_handler (ScreenPtr pScreen);
 
 #if defined(I830_USE_UXA) || defined(I830_USE_EXA)
 dri_bo *i830_get_pixmap_bo (PixmapPtr pixmap);
+void i830_set_pixmap_bo(PixmapPtr pixmap, dri_bo *bo);
 #endif
 
 #ifdef I830_USE_XAA
@@ -271,6 +272,8 @@ typedef struct _I830CrtcPrivateRec {
     
     int			    dpms_mode;
     
+    int			    x, y;
+
     /* Lookup table values to be set when the CRTC is enabled */
     uint8_t lut_r[256], lut_g[256], lut_b[256];
 
@@ -474,6 +477,8 @@ typedef struct _I830Rec {
    int drmMinor;
    Bool allocate_classic_textures;
 
+   Bool can_resize;
+
    Bool want_vblank_interrupts;
 #ifdef DAMAGE
    DamagePtr pDamage;
@@ -910,6 +915,10 @@ Bool i830_unbind_all_memory(ScrnInfoPtr pScrn);
 Bool I830BindAGPMemory(ScrnInfoPtr pScrn);
 Bool I830UnbindAGPMemory(ScrnInfoPtr pScrn);
 
+i830_memory *
+i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox,
+			  Bool secondary);
+
 /* i830_modes.c */
 DisplayModePtr i830_ddc_get_modes(xf86OutputPtr output);
 
diff --git a/src/i830_display.c b/src/i830_display.c
index 2e5d55a..b1ce9e6 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -410,6 +410,9 @@ i830PipeSetBase(xf86CrtcPtr crtc, int x, int y)
 	Start = pI8301->front_buffer_2->offset;
     }
 
+    crtc->x = x;
+    crtc->y = y;
+
     if (IS_I965G(pI830)) {
         OUTREG(dspbase, Offset);
 	POSTING_READ(dspbase);
@@ -1642,10 +1645,34 @@ i830_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
 static void
 i830_crtc_set_origin(xf86CrtcPtr crtc, int x, int y)
 {
-    i830PipeSetBase(crtc, x, y);
+    if (crtc->enabled)
+	i830PipeSetBase(crtc, x, y);
 }
 #endif
 
+/* The screen bo has changed, reset each active crtc to point at
+ * the same location that it currently points at, but in the new bo
+ */
+void
+i830_set_new_crtc_bo(ScrnInfoPtr pScrn)
+{
+    I830Ptr pI830 = I830PTR(pScrn);
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int			i;
+
+    for (i = 0; i < xf86_config->num_crtc; i++) {
+	xf86CrtcPtr crtc = xf86_config->crtc[i];
+
+	if (crtc->enabled) {
+	    I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+	    int plane = intel_crtc->plane;
+	    int dspstride_reg = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
+            OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
+	    i830PipeSetBase(crtc, crtc->x, crtc->y);
+	}
+    }
+}
+
 void
 i830DescribeOutputConfiguration(ScrnInfoPtr pScrn)
 {
diff --git a/src/i830_display.h b/src/i830_display.h
index 1eeb7f1..8d767b1 100644
--- a/src/i830_display.h
+++ b/src/i830_display.h
@@ -31,6 +31,7 @@
 void i830PipeSetBase(xf86CrtcPtr crtc, int x, int y);
 void i830WaitForVblank(ScrnInfoPtr pScrn);
 void i830DescribeOutputConfiguration(ScrnInfoPtr pScrn);
+void i830_set_new_crtc_bo(ScrnInfoPtr pScrn);
 
 xf86CrtcPtr i830GetLoadDetectPipe(xf86OutputPtr output, DisplayModePtr mode, int *dpms_mode);
 void i830ReleaseLoadDetectPipe(xf86OutputPtr output, int dpms_mode);
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 7590257..d366ab6 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -1085,11 +1085,103 @@ I830IsPrimary(ScrnInfoPtr pScrn)
    return TRUE;
 }
 
+
+/*
+ * Adjust *width to allow for tiling if possible
+ */
+static Bool
+i830_tiled_width(I830Ptr i830, int *width, int cpp)
+{
+    Bool    tiled = FALSE;
+
+    /*
+     * Adjust the display width to allow for front buffer tiling if possible
+     */
+    if (i830->tiling) {
+	if (IS_I965G(i830)) {
+	    int tile_pixels = 512 / cpp;
+	    *width = (*width + tile_pixels - 1) &
+		~(tile_pixels - 1);
+	    tiled = TRUE;
+	} else {
+	    /* Good pitches to allow tiling.  Don't care about pitches < 1024
+	     * pixels.
+	     */
+	    static const int pitches[] = {
+		1024,
+		2048,
+		4096,
+		8192,
+		0
+	    };
+	    int i;
+
+	    for (i = 0; pitches[i] != 0; i++) {
+		if (pitches[i] >= *width) {
+		    *width = pitches[i];
+		    tiled = TRUE;
+		    break;
+		}
+	    }
+	}
+    }
+    return tiled;
+}
+
+/*
+ * Pad to accelerator requirement
+ */
+static int
+i830_pad_drawable_width(int width)
+{
+    return (width + 63) & ~63;
+}
+
 static Bool
 i830_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 {
+    I830Ptr	i830 = I830PTR(scrn);
+    int		old_x = scrn->virtualX;
+    int		old_y = scrn->virtualY;
+    int		old_width = scrn->displayWidth;
+
+    if (old_x == width && old_y == height)
+	return TRUE;
+
     scrn->virtualX = width;
     scrn->virtualY = height;
+#ifdef DRI2
+    if (i830->can_resize && i830->front_buffer)
+    {
+	i830_memory *new_front;
+	BoxRec	    mem_box;
+	Bool	    tiled;
+	ScreenPtr   screen = screenInfo.screens[scrn->scrnIndex];
+
+	scrn->displayWidth = i830_pad_drawable_width(width);
+	tiled = i830_tiled_width(i830, &scrn->displayWidth, i830->cpp);
+	xf86DrvMsg(scrn->scrnIndex, X_INFO, "Allocate new frame buffer %dx%d stride %d\n",
+		   width, height, scrn->displayWidth);
+	new_front = i830_allocate_framebuffer(scrn, i830, &mem_box, FALSE);
+	if (!new_front) {
+	    scrn->virtualX = old_x;
+	    scrn->virtualY = old_y;
+	    scrn->displayWidth = old_width;
+	    return FALSE;
+	}
+	i830_free_memory(scrn, i830->front_buffer);
+	i830->front_buffer = new_front;
+	i830_set_pixmap_bo(screen->GetScreenPixmap(screen),
+			   new_front->bo);
+	scrn->fbOffset = i830->front_buffer->offset;
+	screen->ModifyPixmapHeader(screen->GetScreenPixmap(screen),
+				   width, height, -1, -1, scrn->displayWidth * i830->cpp,
+				   NULL);
+	xf86DrvMsg(scrn->scrnIndex, X_INFO, "New front buffer at 0x%lx\n",
+		   i830->front_buffer->offset);
+	i830_set_new_crtc_bo(scrn);
+    }
+#endif
     return TRUE;
 }
 
@@ -1487,8 +1579,7 @@ I830PreInitCrtcConfig(ScrnInfoPtr pScrn)
     /* See i830_exa.c comments for why we limit the framebuffer size like this.
      */
     if (IS_I965G(pI830)) {
-	max_width = 8192;
-	max_height = 8192;
+	max_height = max_width = min(16384 / pI830->cpp, 8192);
     } else {
 	max_width = 2048;
 	max_height = 2048;
@@ -1602,7 +1693,16 @@ I830AccelMethodInit(ScrnInfoPtr pScrn)
     I830SetupOutputs(pScrn);
 
     SaveHWState(pScrn);
-    if (!xf86InitialConfiguration (pScrn, FALSE))
+    pI830->can_resize = FALSE;
+    if (pI830->accel == ACCEL_UXA && pI830->directRenderingType != DRI_XF86DRI)
+	pI830->can_resize = TRUE;
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	       "Resizable framebuffer: %s (%d %d)\n",
+	       pI830->can_resize ? "available" : "not available",
+	       pI830->directRenderingType, pI830->accel);
+
+    if (!xf86InitialConfiguration (pScrn, pI830->can_resize))
     {
 	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
 	RestoreHWState(pScrn);
@@ -2775,7 +2875,6 @@ failed:
 	    tiled ? "T" : "Unt");
     return FALSE;
 }
-
 /*
  * Try to allocate memory in several ways:
  *  1) If direct rendering is enabled, try to allocate enough memory for tiled
@@ -2790,39 +2889,9 @@ i830_memory_init(ScrnInfoPtr pScrn)
 {
     I830Ptr pI830 = I830PTR(pScrn);
     int savedDisplayWidth = pScrn->displayWidth;
-    int i;
     Bool tiled = FALSE;
 
-    /*
-     * Adjust the display width to allow for front buffer tiling if possible
-     */
-    if (pI830->tiling) {
-	if (IS_I965G(pI830)) {
-	    int tile_pixels = 512 / pI830->cpp;
-	    pScrn->displayWidth = (pScrn->displayWidth + tile_pixels - 1) &
-		~(tile_pixels - 1);
-	    tiled = TRUE;
-	} else {
-	    /* Good pitches to allow tiling.  Don't care about pitches < 1024
-	     * pixels.
-	     */
-	    static const int pitches[] = {
-		1024,
-		2048,
-		4096,
-		8192,
-		0
-	    };
-
-	    for (i = 0; pitches[i] != 0; i++) {
-		if (pitches[i] >= pScrn->displayWidth) {
-		    pScrn->displayWidth = pitches[i];
-		    tiled = TRUE;
-		    break;
-		}
-	    }
-	}
-    }
+    tiled = i830_tiled_width(pI830, &pScrn->displayWidth, pI830->cpp);
     /* Set up our video memory allocator for the chosen videoRam */
     if (!i830_allocator_init(pScrn, 0, pScrn->videoRam * KB(1))) {
 	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
@@ -3043,7 +3112,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
    if (!pI830->use_drm_mode)
        hwp = VGAHWPTR(pScrn);
 
-   pScrn->displayWidth = (pScrn->virtualX + 63) & ~63;
+   pScrn->displayWidth = i830_pad_drawable_width(pScrn->virtualX);
 
    /*
     * The "VideoRam" config file parameter specifies the maximum amount of
@@ -3105,7 +3174,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
    /* If DRI hasn't been explicitly disabled, try to initialize it.
     * It will be used by the memory allocator.
     */
-   if (pI830->directRenderingType == DRI_NONE && I830DRIScreenInit(pScreen))
+   if (!pI830->can_resize && pI830->directRenderingType == DRI_NONE && I830DRIScreenInit(pScreen))
        pI830->directRenderingType = DRI_XF86DRI;
 #endif
 
diff --git a/src/i830_exa.c b/src/i830_exa.c
index 3e3487e..ced31a8 100644
--- a/src/i830_exa.c
+++ b/src/i830_exa.c
@@ -758,6 +758,28 @@ i830_get_pixmap_bo(PixmapPtr pixmap)
     return NULL;
 }
 
+void
+i830_set_pixmap_bo(PixmapPtr pixmap, dri_bo *bo)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pixmap->drawable.pScreen->myNum];
+    I830Ptr i830 = I830PTR(pScrn);
+    dri_bo  *old_bo = i830_get_pixmap_bo (pixmap);
+
+    if (old_bo)
+	dri_bo_unreference (old_bo);
+#if I830_USE_UXA
+    if (i830->accel == ACCEL_UXA)
+	dixSetPrivate(&pixmap->devPrivates, &uxa_pixmap_index, bo);
+#endif
+#ifdef XF86DRM_MODE
+    if (i830->accel == ACCEL_EXA) {
+	struct i830_exa_pixmap_priv *driver_priv =
+	    exaGetPixmapDriverPrivate(pixmap);
+	if (driver_priv)
+	    driver_priv->bo = bo;
+    }
+#endif
+}
 #if defined(I830_USE_UXA)
 
 static void
diff --git a/src/i830_memory.c b/src/i830_memory.c
index ca15964..132642f 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -918,10 +918,13 @@ i830_allocate_memory_tiled(ScrnInfoPtr pScrn, const char *name,
     mem = i830_allocate_memory(pScrn, name, aper_size, aper_align, flags);
     if (mem == NULL)
 	return NULL;
+    i830_unbind_memory(pScrn, mem);
     mem->size = size;
     mem->tiling = tile_format;
     mem->pitch = pitch;
     mem->fence_nr = -1;
+    if (pScrn->vtSema || pI830->use_drm_mode)
+	i830_bind_memory(pScrn, mem);
 
 #ifdef XF86DRI
     if (mem->bo != 0) {
@@ -1145,7 +1148,7 @@ IsTileable(ScrnInfoPtr pScrn, int pitch)
  * \param pI830 I830Ptr for the screen being allocated.
  * \param FbMemBox
  */
-static i830_memory *
+i830_memory *
 i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox,
 			  Bool secondary)
 {
@@ -1167,10 +1170,14 @@ i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox,
     /* We'll allocate the fb such that the root window will fit regardless of
      * rotation.
      */
-    if (!pI830->use_drm_mode && pScrn->virtualX > pScrn->virtualY)
-	fb_height = pScrn->virtualX;
-    else
-	fb_height = pScrn->virtualY;
+    fb_height = pScrn->virtualY;
+    if (!pI830->can_resize)
+    {
+	if (!pI830->use_drm_mode && pScrn->virtualX > pScrn->virtualY)
+	    fb_height = pScrn->virtualX;
+	else
+	    fb_height = pScrn->virtualY;
+    }
 
     FbMemBox->x1 = 0;
     FbMemBox->x2 = pScrn->displayWidth;
-- 
1.5.6.5




More information about the Intel-gfx mailing list