diff --git a/src/i830.h b/src/i830.h index 8947524..93006f7 100644 --- a/src/i830.h +++ b/src/i830.h @@ -285,6 +285,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 */ @@ -340,6 +342,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 2df1fcc..85b5c0d 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -654,15 +654,91 @@ 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 (1<<16) +#define FBC_CTL_STRIDE (1<<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_PIPEA (0<<0) +#define FBC_CTL_PIPEB (1<<0) + +/* + * 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) + */ +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; + int pipe = intel_crtc->pipe; + int plane = (pipe == 0 ? FBC_CTL_PIPEA : FBC_CTL_PIPEB); + + /* 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, plane); + + /* enable it... */ + fbc_ctl = INREG(FBC_CONTROL); + fbc_ctl |= FBC_CTL_EN; + 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 +752,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_memory.c b/src/i830_memory.c index afdd93d..c1a3828 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -1022,6 +1022,50 @@ i830_allocate_cursor_buffers(ScrnInfoPtr pScrn) return TRUE; } +static void i830_setup_fb_compression(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + /* Only 965GM & later support this feature */ + if (!IS_I965GM(pI830)) { + pI830->fb_compression = FALSE; + return; + } + + /* + * 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(4), KB(4), + NEED_PHYSICAL_ADDR); + + if (!pI830->compressed_front_buffer) + return; + + 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; + return; + } + + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "allocated compressed framebuffer, phys: 0x%16lx, size: %ld\n", + pI830->compressed_front_buffer->bus_addr, + pI830->compressed_front_buffer->size); + pI830->fb_compression = TRUE; +} /* * Allocate memory for 2D operation. This includes the (front) framebuffer, * ring buffer, scratch memory, HW cursor. @@ -1046,6 +1090,8 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn) /* Allocate the ring buffer first, so it ends up in stolen mem. */ i830_allocate_ringbuffer(pScrn); + 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,