diff options
-rw-r--r-- | man/intel.man | 7 | ||||
-rw-r--r-- | src/i830.h | 7 | ||||
-rw-r--r-- | src/i830_display.c | 100 | ||||
-rw-r--r-- | src/i830_driver.c | 18 | ||||
-rw-r--r-- | src/i830_memory.c | 72 | ||||
-rw-r--r-- | src/i830_reg.h | 24 |
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. @@ -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) |