summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/intel.man7
-rw-r--r--src/i830.h7
-rw-r--r--src/i830_display.c100
-rw-r--r--src/i830_driver.c18
-rw-r--r--src/i830_memory.c72
-rw-r--r--src/i830_reg.h24
6 files changed, 225 insertions, 3 deletions
diff --git a/man/intel.man b/man/intel.man
index 75280a7c..3173bc75 100644
--- a/man/intel.man
+++ b/man/intel.man
@@ -75,6 +75,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..1358e3ee 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;
@@ -527,6 +530,10 @@ typedef struct _I830Rec {
CARD32 savePaletteB[256];
CARD32 saveSWF[17];
CARD32 saveBLC_PWM_CTL;
+ CARD32 saveFBC_CFB_BASE;
+ CARD32 saveFBC_LL_BASE;
+ CARD32 saveFBC_CONTROL2;
+ CARD32 saveFBC_CONTROL;
enum last_3d *last_3d;
diff --git a/src/i830_display.c b/src/i830_display.c
index ebde5256..0befef9d 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -38,6 +38,7 @@
#include "xf86.h"
#include "i830.h"
+#include "i830_reg.h"
#include "i830_bios.h"
#include "i830_display.h"
#include "i830_debug.h"
@@ -653,9 +654,104 @@ i830_crtc_unlock (xf86CrtcPtr crtc)
#endif
}
+static Bool
+i830_use_fb_compression(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ int pipe = intel_crtc->pipe;
+ int plane = (pipe == 0 ? FBC_CTL_PIPEA : FBC_CTL_PIPEB);
+
+ if (!pI830->fb_compression)
+ return FALSE;
+
+ /* Pre-965 only supports plane A, which is synonymous with pipe A for now */
+ if (!IS_I965GM(pI830) && plane != FBC_CTL_PIPEA)
+ return FALSE;
+
+ /* Need 15, 16, or 32 (w/alpha) pixel format */
+ if (!(pScrn->bitsPerPixel == 16 || /* covers 15 bit mode as well */
+ pScrn->bitsPerPixel == 32)) /* mode_set dtrt if fbc is in use */
+ return FALSE;
+
+ /*
+ * No checks for pixel multiply, incl. horizontal, or interlaced modes
+ * since they're currently unused.
+ */
+ return TRUE;
+}
+
+/*
+ * 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)
+ * - uncompressed fb is <= 2048 in width, 0 mod 8
+ * - uncompressed fb is <= 1536 in height, 0 mod 2
+ * - SR display watermarks must be equal between 16bpp and 32bpp?
+ *
+ * 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_LL_SIZE;
+
+ 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 + FBC_LL_PAD);
+ 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);
+}
+
+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)
{
+ /* Temporarily turn off FB compression during modeset */
+ i830_disable_fb_compression(crtc);
crtc->funcs->dpms (crtc, DPMSModeOff);
}
@@ -675,6 +771,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 (i830_use_fb_compression(crtc))
+ i830_enable_fb_compression(crtc);
}
void
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 7f1fe2cc..5f934fee 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -192,6 +192,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "vbe.h"
#include "shadow.h"
#include "i830.h"
+#include "i830_reg.h"
#include "i830_display.h"
#include "i830_debug.h"
#include "i830_bios.h"
@@ -285,6 +286,7 @@ typedef enum {
OPTION_COLOR_KEY,
OPTION_CHECKDEVICES,
OPTION_MODEDEBUG,
+ OPTION_FBC,
#ifdef XF86DRI_MM
OPTION_INTELTEXPOOL,
OPTION_INTELMMSIZE,
@@ -306,6 +308,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},
@@ -1748,6 +1751,11 @@ SaveHWState(ScrnInfoPtr pScrn)
vgaRegPtr vgaReg = &hwp->SavedReg;
int i;
+ pI830->saveFBC_CFB_BASE = INREG(FBC_CFB_BASE);
+ pI830->saveFBC_LL_BASE = INREG(FBC_LL_BASE);
+ pI830->saveFBC_CONTROL2 = INREG(FBC_CONTROL2);
+ pI830->saveFBC_CONTROL = INREG(FBC_CONTROL);
+
/* Save video mode information for native mode-setting. */
pI830->saveDSPACNTR = INREG(DSPACNTR);
pI830->savePIPEACONF = INREG(PIPEACONF);
@@ -1972,6 +1980,11 @@ RestoreHWState(ScrnInfoPtr pScrn)
OUTREG(SWF31, pI830->saveSWF[15]);
OUTREG(SWF32, pI830->saveSWF[16]);
+ OUTREG(FBC_CFB_BASE, pI830->saveFBC_CFB_BASE);
+ OUTREG(FBC_LL_BASE, pI830->saveFBC_LL_BASE);
+ OUTREG(FBC_CONTROL2, pI830->saveFBC_CONTROL2);
+ OUTREG(FBC_CONTROL, pI830->saveFBC_CONTROL);
+
vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS);
vgaHWLock(hwp);
@@ -2305,6 +2318,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..71346004 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -104,6 +104,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "i830.h"
#include "i810_reg.h"
+#include "i830_reg.h"
#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
@@ -902,8 +903,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 +1023,62 @@ 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;
+ }
+
+ /* Clear out any stale state */
+ OUTREG(FBC_CFB_BASE, 0);
+ OUTREG(FBC_LL_BASE, 0);
+ OUTREG(FBC_CONTROL2, 0);
+ OUTREG(FBC_CONTROL, 0);
+
+ /*
+ * 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",
+ FBC_LL_SIZE + FBC_LL_PAD, 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 +1103,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,
@@ -1249,7 +1309,8 @@ i830_allocate_depthbuffer(ScrnInfoPtr pScrn)
i830_allocate_memory_tiled(pScrn, "depth buffer", size, pitch,
GTT_PAGE_SIZE, ALIGN_BOTH_ENDS,
tile_format);
- pI830->depth_tiled = FENCE_XMAJOR;
+ pI830->depth_tiled = (tile_format == TILING_YMAJOR) ? FENCE_YMAJOR :
+ FENCE_XMAJOR;
}
/* Otherwise, allocate it linear. */
@@ -1389,6 +1450,11 @@ i830_set_fence(ScrnInfoPtr pScrn, int nr, unsigned int offset,
assert(tile_format != TILING_NONE);
if (IS_I965G(pI830)) {
+ if (tile_format == TILING_XMAJOR)
+ pitch = 512;
+ else
+ pitch = 128;
+
if (nr < 0 || nr >= FENCE_NEW_NR) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"i830_set_fence(): fence %d out of range\n",nr);
diff --git a/src/i830_reg.h b/src/i830_reg.h
index 7a8df9f8..d1670c3e 100644
--- a/src/i830_reg.h
+++ b/src/i830_reg.h
@@ -29,6 +29,30 @@
#ifndef _I830_REG_H_
#define _I830_REG_H_
+/* Framebuffer compression */
+#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_LL_SIZE (1536)
+#define FBC_LL_PAD (32)
+
#define I830_SET_FIELD( var, mask, value ) (var &= ~(mask), var |= value)
#define CMD_3D (0x3<<29)