summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/intel.man7
-rw-r--r--src/i830.h3
-rw-r--r--src/i830_display.c99
-rw-r--r--src/i830_driver.c7
-rw-r--r--src/i830_memory.c57
5 files changed, 171 insertions, 2 deletions
diff --git a/man/intel.man b/man/intel.man
index 89916194..3e443cd2 100644
--- a/man/intel.man
+++ b/man/intel.man
@@ -77,6 +77,13 @@ driver attempts to allocate space for at 3 screenfuls of pixmaps plus an
HD-sized XV video. The default used for a specific configuration can be found
by examining the __xservername__ log file.
.TP
+.BI "Option \*qFrameBufferCompression\*q \*q" boolean \*q
+This option controls whether the framebuffer compression feature is enabled.
+If possible, the front buffer will be allocated in a tiled format and compressed
+periodically to save memory bandwidth and power.
+.TP
+This option is only available on mobile chipsets.
+.TP
.BI "Option \*qDRI\*q \*q" boolean \*q
Disable or enable DRI support.
Default: DRI is enabled for configurations where it is supported.
diff --git a/src/i830.h b/src/i830.h
index 9dda33a7..29982ecd 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -287,6 +287,8 @@ typedef struct _I830Rec {
i830_memory *front_buffer;
i830_memory *front_buffer_2;
+ i830_memory *compressed_front_buffer;
+ i830_memory *compressed_ll_buffer;
/* One big buffer for all cursors for kernels that support this */
i830_memory *cursor_mem;
/* separate small buffers for kernels that support this */
@@ -342,6 +344,7 @@ typedef struct _I830Rec {
Bool allowPageFlip;
Bool TripleBuffer;
Bool disableTiling;
+ Bool fb_compression;
int backPitch;
diff --git a/src/i830_display.c b/src/i830_display.c
index aba86ae7..f3b24b20 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -653,15 +653,110 @@ i830_crtc_unlock (xf86CrtcPtr crtc)
#endif
}
+#define FBC_CFB_BASE 0x03200 /* 4k page aligned */
+#define FBC_LL_BASE 0x03204 /* 4k page aligned */
+#define FBC_CONTROL 0x03208
+#define FBC_CTL_EN (1<<31)
+#define FBC_CTL_PERIODIC (1<<30)
+#define FBC_CTL_INTERVAL_SHIFT (16)
+#define FBC_CTL_STRIDE_SHIFT (5)
+#define FBC_CTL_FENCENO (1<<0)
+#define FBC_COMMAND 0x0320c
+#define FBC_CMD_COMPRESS (1<<0)
+#define FBC_STATUS 0x03210
+#define FBC_STAT_COMPRESSING (1<<31)
+#define FBC_STAT_COMPRESSED (1<<30)
+#define FBC_STAT_MODIFIED (1<<29)
+#define FBC_STAT_CURRENT_LINE (1<<0)
+#define FBC_CONTROL2 0x03214
+#define FBC_CTL_CPU_FENCE (1<<1)
+#define FBC_CTL_PIPEA (0<<0)
+#define FBC_CTL_PIPEB (1<<0)
+
+#define FBC_COMPRESSED_LINES (1536+32)
+
+/*
+ * Several restrictions:
+ * - DSP[AB]CNTR - no line duplication && no pixel multiplier
+ * - pixel format == 15 bit, 16 bit, or 32 bit xRGB_8888
+ * - no alpha buffer discard
+ * - no dual wide display
+ * - progressive mode only (DSP[AB]CNTR)
+ *
+ * FIXME: verify above conditions are true
+ */
+static void
+i830_enable_fb_compression(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ uint32_t fbc_ctl;
+ unsigned long compressed_stride;
+ int pipe = intel_crtc->pipe;
+ int plane = (pipe == 0 ? FBC_CTL_PIPEA : FBC_CTL_PIPEB);
+ unsigned long uncompressed_stride = pScrn->displayWidth * pI830->cpp;
+ unsigned long interval = 1000;
+
+ compressed_stride = pI830->compressed_front_buffer->size /
+ FBC_COMPRESSED_LINES;
+
+ if (uncompressed_stride < compressed_stride)
+ compressed_stride = uncompressed_stride;
+
+ /* FBC_CTL wants 64B units */
+ compressed_stride = (compressed_stride / 64) - 1;
+
+ /* Set it up... */
+ OUTREG(FBC_CFB_BASE, pI830->compressed_front_buffer->bus_addr);
+ OUTREG(FBC_LL_BASE, pI830->compressed_ll_buffer->bus_addr);
+ OUTREG(FBC_CONTROL2, FBC_CTL_CPU_FENCE | plane);
+
+ /* enable it... */
+ fbc_ctl = INREG(FBC_CONTROL);
+ fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC;
+ fbc_ctl |= (compressed_stride & 0xff) << FBC_CTL_STRIDE_SHIFT;
+ fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
+ OUTREG(FBC_CONTROL, fbc_ctl);
+
+ /* and request immediate compression */
+ OUTREG(FBC_COMMAND, FBC_CMD_COMPRESS);
+}
+
+static void
+i830_disable_fb_compression(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ uint32_t fbc_ctl;
+
+ /* Disable compression */
+ fbc_ctl = INREG(FBC_CONTROL);
+ fbc_ctl &= ~FBC_CTL_EN;
+ OUTREG(FBC_CONTROL, fbc_ctl);
+
+ /* Wait for compressing bit to clear */
+ while (INREG(FBC_STATUS) & FBC_STAT_COMPRESSING)
+ ; /* nothing */
+}
+
static void
i830_crtc_prepare (xf86CrtcPtr crtc)
{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
crtc->funcs->dpms (crtc, DPMSModeOff);
+
+ /* Temporarily turn off FB compression during modeset */
+ if (pI830->fb_compression)
+ i830_disable_fb_compression(crtc);
}
static void
i830_crtc_commit (xf86CrtcPtr crtc)
{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
Bool deactivate = FALSE;
@@ -675,6 +770,10 @@ i830_crtc_commit (xf86CrtcPtr crtc)
xf86_reload_cursors (crtc->scrn->pScreen);
if (deactivate)
i830_pipe_a_require_deactivate (crtc->scrn);
+
+ /* Reenable FB compression if possible */
+ if (pI830->fb_compression)
+ i830_enable_fb_compression(crtc);
}
void
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 7f1fe2cc..42d0f872 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -285,6 +285,7 @@ typedef enum {
OPTION_COLOR_KEY,
OPTION_CHECKDEVICES,
OPTION_MODEDEBUG,
+ OPTION_FBC,
#ifdef XF86DRI_MM
OPTION_INTELTEXPOOL,
OPTION_INTELMMSIZE,
@@ -306,6 +307,7 @@ static OptionInfoRec I830Options[] = {
{OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE},
{OPTION_CHECKDEVICES, "CheckDevices",OPTV_BOOLEAN, {0}, FALSE},
{OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_FBC, "FrameBufferCompression", OPTV_BOOLEAN, {0}, FALSE},
#ifdef XF86DRI_MM
{OPTION_INTELTEXPOOL,"Legacy3D", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_INTELMMSIZE, "AperTexSize", OPTV_INTEGER, {0}, FALSE},
@@ -2305,6 +2307,11 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
pI830->CacheLines = -1;
}
+ if (xf86ReturnOptValBool(pI830->Options, OPTION_FBC, FALSE))
+ pI830->fb_compression = TRUE;
+ else
+ pI830->fb_compression = FALSE;
+
pI830->disableTiling = FALSE;
if (I830IsPrimary(pScrn)) {
diff --git a/src/i830_memory.c b/src/i830_memory.c
index afdd93d7..5e553f18 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -902,8 +902,8 @@ i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox,
name = secondary ? "secondary front buffer" : "front buffer";
/* Attempt to allocate it tiled first if we have page flipping on. */
- if (!pI830->disableTiling && pI830->allowPageFlip &&
- IsTileable(pScrn, pitch))
+ if ((!pI830->disableTiling && pI830->allowPageFlip &&
+ IsTileable(pScrn, pitch)) || pI830->fb_compression)
{
/* XXX: probably not the case on 965 */
if (IS_I9XX(pI830))
@@ -1022,6 +1022,56 @@ i830_allocate_cursor_buffers(ScrnInfoPtr pScrn)
return TRUE;
}
+static void i830_setup_fb_compression(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ /* Only mobile chips since 845 support this feature */
+ if (!IS_MOBILE(pI830)) {
+ pI830->fb_compression = FALSE;
+ goto out;
+ }
+
+ /*
+ * Compressed framebuffer limitations:
+ * - contiguous, physical, uncached memory
+ * - ideally as large as the front buffer(s), smaller sizes cache less
+ * - uncompressed buffer must be tiled w/pitch 2k-16k
+ * - uncompressed fb is <= 2048 in width, 0 mod 8
+ * - uncompressed fb is <= 1536 in height, 0 mod 2
+ * - compressed fb stride is <= uncompressed stride
+ * - SR display watermarks must be equal between 16bpp and 32bpp?
+ * - both compressed and line buffers must be in stolen memory
+ */
+ pI830->compressed_front_buffer =
+ i830_allocate_memory(pScrn, "compressed frame buffer",
+ MB(6), KB(4),
+ NEED_PHYSICAL_ADDR);
+
+ if (!pI830->compressed_front_buffer) {
+ pI830->fb_compression = FALSE;
+ goto out;
+ }
+
+ pI830->compressed_ll_buffer =
+ i830_allocate_memory(pScrn, "compressed ll buffer",
+ 1568, KB(4), NEED_PHYSICAL_ADDR);
+ if (!pI830->compressed_ll_buffer) {
+ i830_free_memory(pScrn, pI830->compressed_front_buffer);
+ pI830->fb_compression = FALSE;
+ goto out;
+ }
+
+out:
+ if (pI830->fb_compression)
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Framebuffer compression "
+ "enabled\n");
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Allocation error, framebuffer"
+ " compression disabled\n");
+
+ return;
+}
/*
* Allocate memory for 2D operation. This includes the (front) framebuffer,
* ring buffer, scratch memory, HW cursor.
@@ -1046,6 +1096,9 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn)
/* Allocate the ring buffer first, so it ends up in stolen mem. */
i830_allocate_ringbuffer(pScrn);
+ if (pI830->fb_compression)
+ i830_setup_fb_compression(pScrn);
+
/* Next, allocate other fixed-size allocations we have. */
if (!pI830->SWCursor && !i830_allocate_cursor_buffers(pScrn)) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,