diff --git a/man/intel.man b/man/intel.man index 8991619..3e443cd 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 9dda33a..29982ec 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 f6e99be..8bbd4df 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -654,15 +654,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; @@ -676,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 (pI830->fb_compression) + i830_enable_fb_compression(crtc); } void diff --git a/src/i830_driver.c b/src/i830_driver.c index 7f1fe2c..42d0f87 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 afdd93d..5e553f1 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,