[Intel-gfx] [PATCH] Resize framebuffer on screen size change (requires UXA and DRI2)

Keith Packard keithp at keithp.com
Tue Dec 16 00:57:38 CET 2008


Signed-off-by: Keith Packard <keithp at keithp.com>
---
 src/i830.h         |    9 +++
 src/i830_display.c |   31 +++++++++--
 src/i830_display.h |    1 +
 src/i830_driver.c  |  149 ++++++++++++++++++++++++++++++++++++++-------------
 src/i830_exa.c     |   27 +++++++++
 src/i830_memory.c  |  120 +++--------------------------------------
 6 files changed, 184 insertions(+), 153 deletions(-)

diff --git a/src/i830.h b/src/i830.h
index fe7c8b2..d5b0e5d 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
@@ -273,6 +274,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];
 
@@ -476,6 +479,8 @@ typedef struct _I830Rec {
    int drmMinor;
    Bool allocate_classic_textures;
 
+   Bool can_resize;
+
    Bool want_vblank_interrupts;
 #ifdef DAMAGE
    DamagePtr pDamage;
@@ -915,6 +920,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 e3236c9..a4af8ad 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -387,12 +387,14 @@ i830PipeSetBase(xf86CrtcPtr crtc, int x, int y)
     I830CrtcPrivatePtr	intel_crtc = crtc->driver_private;
     int pipe = intel_crtc->pipe;
     int plane = intel_crtc->plane;
-    unsigned long Start, Offset;
+    unsigned long Start, Offset, Stride;
     int dspbase = (plane == 0 ? DSPABASE : DSPBBASE);
     int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
     int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
+    int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
 
     Offset = ((y * pScrn->displayWidth + x) * pI830->cpp);
+    Stride = pScrn->displayWidth * pI830->cpp;
     if (pI830->front_buffer == NULL) {
 	/* During startup we may be called as part of monitor detection while
 	 * there is no memory allocation done, so just supply a dummy base
@@ -403,6 +405,7 @@ i830PipeSetBase(xf86CrtcPtr crtc, int x, int y)
 	/* offset is done by shadow painting code, not here */
 	Start = (char *)crtc->rotatedData - (char *)pI830->FbBase;
 	Offset = 0;
+	Stride = intel_crtc->rotate_mem->pitch;
     } else if (I830IsPrimary(pScrn)) {
 	Start = pI830->front_buffer->offset;
     } else {
@@ -410,6 +413,10 @@ i830PipeSetBase(xf86CrtcPtr crtc, int x, int y)
 	Start = pI8301->front_buffer_2->offset;
     }
 
+    crtc->x = x;
+    crtc->y = y;
+
+    OUTREG(dspstride, Stride);
     if (IS_I965G(pI830)) {
         OUTREG(dspbase, Offset);
 	POSTING_READ(dspbase);
@@ -1199,7 +1206,6 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
     int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
     int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
     int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-    int dspstride_reg = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
     int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
     int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
     int pipestat_reg = (pipe == 0) ? PIPEASTAT : PIPEBSTAT;
@@ -1495,7 +1501,6 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
 	((adjusted_mode->CrtcVBlankEnd - 1) << 16));
     OUTREG(vsync_reg, (adjusted_mode->CrtcVSyncStart - 1) |
 	((adjusted_mode->CrtcVSyncEnd - 1) << 16));
-    OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
     /* pipesrc and dspsize control the size that is scaled from, which should
      * always be the user's requested size.
      */
@@ -1644,10 +1649,28 @@ 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)
+{
+    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 && !crtc->transform_in_use)
+	    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 d3b539a..358b485 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -1085,11 +1085,108 @@ I830IsPrimary(ScrnInfoPtr pScrn)
    return TRUE;
 }
 
+
+/*
+ * Adjust *width to allow for tiling if possible
+ */
+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
+ */
+int
+i830_pad_drawable_width(int width, int cpp)
+{
+    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, *old_front;
+	BoxRec	    mem_box;
+	Bool	    tiled;
+	ScreenPtr   screen = screenInfo.screens[scrn->scrnIndex];
+
+	scrn->displayWidth = i830_pad_drawable_width(width, i830->cpp);
+	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);
+	I830Sync(scrn);
+	i830WaitForVblank(scrn);
+	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;
+	}
+	old_front = 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);
+	I830Sync(scrn);
+	i830WaitForVblank(scrn);
+	i830_free_memory(scrn, old_front);
+    }
+#endif
     return TRUE;
 }
 
@@ -1487,8 +1584,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;
@@ -1595,7 +1691,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);
@@ -2760,7 +2865,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
@@ -2775,39 +2879,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,
@@ -3028,7 +3102,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, pI830->cpp);
 
    /*
     * The "VideoRam" config file parameter specifies the maximum amount of
@@ -3092,8 +3166,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
     */
    if (pI830->directRenderingType == DRI_NONE && pI830->SWCursor)
        pI830->directRenderingType = DRI_DISABLED;
-
-   if (pI830->directRenderingType == DRI_NONE && I830DRIScreenInit(pScreen))
+   if (!pI830->can_resize && pI830->directRenderingType == DRI_NONE && I830DRIScreenInit(pScreen))
        pI830->directRenderingType = DRI_XF86DRI;
 
    if (pI830->directRenderingType == DRI_XF86DRI) {
diff --git a/src/i830_exa.c b/src/i830_exa.c
index 3e3487e..ee279d5 100644
--- a/src/i830_exa.c
+++ b/src/i830_exa.c
@@ -758,6 +758,32 @@ 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) {
+	dri_bo_reference(bo);
+	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) {
+	    dri_bo_reference(bo);
+	    driver_priv->bo = bo;
+	}
+    }
+#endif
+}
 #if defined(I830_USE_UXA)
 
 static void
@@ -893,6 +919,7 @@ void i830_uxa_create_screen_resources(ScreenPtr pScreen)
     if (bo != NULL) {
 	PixmapPtr   pixmap = pScreen->GetScreenPixmap(pScreen);
 	i830_uxa_set_pixmap_bo (pixmap, bo);
+	dri_bo_reference(bo);
     }
 }
 
diff --git a/src/i830_memory.c b/src/i830_memory.c
index a5e7dcd..45aa109 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -1128,7 +1128,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)
 {
@@ -1150,10 +1150,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;
@@ -2123,114 +2127,8 @@ Bool i830_allocate_xvmc_buffer(ScrnInfoPtr pScrn, const char *name,
 }
 #endif
 
-#if 0
-static i830_memory *
-i830_allocate_framebuffer_new(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox)
-{
-    unsigned int pitch = pScrn->displayWidth * pI830->cpp;
-    unsigned long minspace, avail;
-    int cacheLines;
-    int align;
-    long size, fb_height;
-    char *name;
-    int flags;
-    i830_memory *front_buffer = NULL;
-    Bool tiling;
-
-    flags = ALLOW_SHARING;
-
-    /* Clear everything first. */
-    memset(FbMemBox, 0, sizeof(*FbMemBox));
-
-    fb_height = pScrn->virtualY;
-
-    FbMemBox->x1 = 0;
-    FbMemBox->x2 = pScrn->displayWidth;
-    FbMemBox->y1 = 0;
-    FbMemBox->y2 = fb_height;
-
-    /* Calculate how much framebuffer memory to allocate.  For the
-     * initial allocation, calculate a reasonable minimum.  This is
-     * enough for the virtual screen size, plus some pixmap cache
-     * space if we're using XAA.
-     */
-    minspace = pitch * pScrn->virtualY;
-    avail = pScrn->videoRam * 1024;
-    cacheLines = 0;
-
-    size = pitch * (fb_height + cacheLines);
-    size = ROUND_TO_PAGE(size);
-
-    name = "front buffer";
-
-    /* Front buffer tiling has to be disabled with G965 XAA because some of the
-     * acceleration operations (non-XY COLOR_BLT) can't be done to tiled
-     * buffers.
-     */
-    if (!(pI830->accel == ACCEL_EXA) && IS_I965G(pI830))
-	tiling = FALSE;
-    else
-	tiling = pI830->tiling;
-
-    if (pI830->use_drm_mode)
-      tiling = FALSE;
-
-    /* Attempt to allocate it tiled first if we have page flipping on. */
-    if (tiling && IsTileable(pScrn, pitch)) {
-	/* XXX: probably not the case on 965 */
-	if (IS_I9XX(pI830))
-	    align = MB(1);
-	else
-	    align = KB(512);
-	front_buffer = i830_allocate_memory_tiled(pScrn, name, size,
-						  pitch, align, flags,
-						  TILE_XMAJOR);
-    }
-
-    /* If not, attempt it linear */
-    if (front_buffer == NULL) {
-	front_buffer = i830_allocate_memory(pScrn, name, size, KB(64), flags);
-    }
-
-    if (front_buffer == NULL) {
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate "
-		   "framebuffer. Is your VideoRAM set too low?\n");
-
-	return NULL;
-    }
-
-    return front_buffer;
-}
-#endif
 uint32_t
 i830_create_new_fb(ScrnInfoPtr pScrn, int width, int height, int *pitch)
 {
     return 0;
-
-#if 0
-    I830Ptr pI830 = I830PTR(pScrn);
-    i830_memory *old_buffer;
-
-    pScrn->virtualX = width;
-    pScrn->virtualY = height;
-    pScrn->displayWidth = (pScrn->virtualX + 63) & ~63;
-
-    *pitch = pScrn->displayWidth * pI830->cpp;
-
-    old_buffer = pI830->front_buffer;
-
-    pI830->front_buffer =
-	i830_allocate_framebuffer_new(pScrn, pI830, &pI830->FbMemBox);
-
-    ErrorF("old front size %08lx, new front size %08lx\n",
-	   old_buffer->bo->size, pI830->front_buffer->bo->size);
-    ErrorF("old front offset %08lx, new front offset %08lx\n",
-	   old_buffer->bo->offset, pI830->front_buffer->bo->offset);
-
-    i830_free_memory(pScrn, old_buffer);
-
-    i830_update_front_offset(pScrn);
-
-    return pI830->front_buffer->bo->handle;
-#endif
 }
-- 
1.5.6.5




More information about the Intel-gfx mailing list