diff --git a/man/intel.man b/man/intel.man index 05aa678..6330e4b 100644 --- a/man/intel.man +++ b/man/intel.man @@ -92,6 +92,16 @@ performance. .IP Default: enabled. .TP +.BI "Option \*qSwapbuffersWait\*q \*q" boolean \*q +This option controls the behavior of glXSwapBuffers and glXCopySubBufferMESA +calls by GL applications. If enabled, the calls will avoid tearing by making +sure the display scanline is outside of the area to be copied before the copy +occurs. If disabled, no scanline synchronization is performed, meaning tearing +will likely occur. Note that when enabled, this option can adversely affect +the framerate of applications that render frames at less than refresh rate. +.IP +Default: enabled. +.TP .BI "Option \*qDRI\*q \*q" boolean \*q Disable or enable DRI support. .IP diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 02a71ae..8f45e84 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -71,7 +71,7 @@ typedef struct { int num_props; drmmode_prop_ptr props; void *private_data; - /* this is used to store private data */ + int dpms_mode; } drmmode_output_private_rec, *drmmode_output_private_ptr; static void @@ -727,6 +727,7 @@ drmmode_output_dpms(xf86OutputPtr output, int mode) drmmode_output->output_id, props->prop_id, mode); + drmmode_output->dpms_mode = mode; drmModeFreeProperty(props); return; } @@ -734,6 +735,14 @@ drmmode_output_dpms(xf86OutputPtr output, int mode) } } +int +drmmode_output_dpms_status(xf86OutputPtr output) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + + return drmmode_output->dpms_mode; +} + static Bool drmmode_property_ignore(drmModePropertyPtr prop) { diff --git a/src/i830.h b/src/i830.h index 19b189c..25ed424 100644 --- a/src/i830.h +++ b/src/i830.h @@ -414,6 +414,7 @@ typedef struct _I830Rec { Bool tiling; Bool fb_compression; + Bool swapbuffers_wait; Bool CursorNeedsPhysical; @@ -690,7 +691,10 @@ void I830DRI2CloseScreen(ScreenPtr pScreen); extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp); extern int drmmode_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc); +extern int drmmode_output_dpms_status(xf86OutputPtr output); +extern Bool i830_crtc_on(xf86CrtcPtr crtc); +extern int i830_crtc_to_pipe(xf86CrtcPtr crtc); extern Bool I830AccelInit(ScreenPtr pScreen); extern void I830SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, diff --git a/src/i830_display.c b/src/i830_display.c index a7eafb9..2af5d60 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -1256,6 +1256,7 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode) case DPMSModeOff: if ((pipe == 0) && (pI830->quirk_flag & QUIRK_PIPEA_FORCE)) disable_pipe = FALSE; + intel_batch_wait_last(pScrn); i830_crtc_disable(crtc, disable_pipe); break; } diff --git a/src/i830_dri.c b/src/i830_dri.c index d00b42c..edba573 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -299,7 +299,7 @@ I830DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, ValidateGC(dst, pGC); /* Wait for the scanline to be outside the region to be copied */ - if (pixmap_is_scanout(get_drawable_pixmap(dst))) { + if (pI830->swapbuffers_wait && pixmap_is_scanout(get_drawable_pixmap(dst))) { BoxPtr box; BoxRec crtcbox; int y1, y2; @@ -311,12 +311,7 @@ I830DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, /* Make sure the CRTC is valid and this is the real front buffer */ if (crtc != NULL && !crtc->rotatedData) { - if (pI830->use_drm_mode) - pipe = drmmode_get_pipe_from_crtc_id(pI830->bufmgr, crtc); - else { - I830CrtcPrivatePtr intel_crtc = crtc->driver_private; - pipe = intel_crtc->pipe; - } + pipe = i830_crtc_to_pipe(crtc); if (pipe == 0) { event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; diff --git a/src/i830_driver.c b/src/i830_driver.c index 9d38fba..b9b9d0b 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -171,6 +171,7 @@ typedef enum { OPTION_LVDS24BITMODE, OPTION_FBC, OPTION_TILING, + OPTION_SWAPBUFFERS_WAIT, OPTION_LVDSFIXEDMODE, OPTION_FORCEENABLEPIPEA, #ifdef INTEL_XVMC @@ -189,6 +190,7 @@ static OptionInfoRec I830Options[] = { {OPTION_LVDS24BITMODE, "LVDS24Bit", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_FBC, "FramebufferCompression", OPTV_BOOLEAN, {0}, TRUE}, {OPTION_TILING, "Tiling", OPTV_BOOLEAN, {0}, TRUE}, + {OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN, {0}, TRUE}, {OPTION_LVDSFIXEDMODE, "LVDSFixedMode", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_FORCEENABLEPIPEA, "ForceEnablePipeA", OPTV_BOOLEAN, {0}, FALSE}, #ifdef INTEL_XVMC @@ -2454,6 +2456,49 @@ i830_init_bufmgr(ScrnInfoPtr pScrn) } } +Bool i830_crtc_on(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + I830Ptr pI830 = I830PTR(pScrn); + + if (pI830->use_drm_mode) { + int i, active_outputs = 0; + + /* Kernel manages CRTC status based out output config */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + if (drmmode_output_dpms_status(output) == DPMSModeOn) + active_outputs++; + } + + if (active_outputs) + return TRUE; + return FALSE; + } else { + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + + if (intel_crtc->dpms_mode == DPMSModeOn) + return TRUE; + return FALSE; + } +} + +int i830_crtc_to_pipe(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + int pipe; + + if (pI830->use_drm_mode) { + pipe = drmmode_get_pipe_from_crtc_id(pI830->bufmgr, crtc); + } else { + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + pipe = intel_crtc->pipe; + } + + return pipe; +} static void I830AdjustMemory(ScreenPtr pScreen) @@ -2663,10 +2708,23 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) pI830->fb_compression = FALSE; } + /* SwapBuffers delays to avoid tearing */ + pI830->swapbuffers_wait = TRUE; + + /* Allow user override if they set a value */ + if (xf86IsOptionSet(pI830->Options, OPTION_SWAPBUFFERS_WAIT)) { + if (xf86ReturnOptValBool(pI830->Options, OPTION_SWAPBUFFERS_WAIT, FALSE)) + pI830->swapbuffers_wait = TRUE; + else + pI830->swapbuffers_wait = FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Framebuffer compression %sabled\n", pI830->fb_compression ? "en" : "dis"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Tiling %sabled\n", pI830->tiling ? "en" : "dis"); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "SwapBuffers wait %sabled\n", + pI830->swapbuffers_wait ? "en" : "dis"); pI830->last_3d = LAST_3D_OTHER; pI830->overlayOn = FALSE; diff --git a/src/i830_video.c b/src/i830_video.c index 1ff80a0..d543cc4 100644 --- a/src/i830_video.c +++ b/src/i830_video.c @@ -1734,6 +1734,11 @@ i830_covering_crtc (ScrnInfoPtr pScrn, for (c = 0; c < xf86_config->num_crtc; c++) { crtc = xf86_config->crtc[c]; + + /* If the CRTC is off, treat it as not covering */ + if (!i830_crtc_on(crtc)) + continue; + i830_crtc_box (crtc, &crtc_box); i830_box_intersect (&cover_box, &crtc_box, box); coverage = i830_box_area (&cover_box); @@ -2491,14 +2496,8 @@ I830PutImage(ScrnInfoPtr pScrn, int y1, y2; int pipe = -1, event, load_scan_lines_pipe; - if (pixmap_is_scanout(pPixmap)) { - if (pI830->use_drm_mode) - pipe = drmmode_get_pipe_from_crtc_id(pI830->bufmgr, crtc); - else { - I830CrtcPrivatePtr intel_crtc = crtc->driver_private; - pipe = intel_crtc->pipe; - } - } + if (pixmap_is_scanout(pPixmap)) + pipe = i830_crtc_to_pipe(crtc); if (pipe >= 0) { if (pipe == 0) {