From 3ff978c55b166fd28ddd70cba455fa1c07dc616b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 16 Jul 2008 03:14:06 -0400 Subject: [PATCH] First pass at tear-free accel if the dest pixmap is the front buffer, stall the pipe until the vline is outside the active area. For EXA, pick crtc based on the larger mode area; ideally we'd have one pixmap per crtc. For Xv, use dst window area to determine crtc. --- src/atombios_crtc.c | 4 ++++ src/legacy_crtc.c | 19 +++++++++++++++++-- src/radeon.h | 2 ++ src/radeon_commonfuncs.c | 33 +++++++++++++++++++++++++++++++++ src/radeon_exa.c | 27 +++++++++++++++++++++++++++ src/radeon_exa_funcs.c | 9 ++++++++- src/radeon_exa_render.c | 6 ++++++ src/radeon_probe.h | 2 ++ src/radeon_reg.h | 8 ++++++++ src/radeon_textured_videofuncs.c | 8 ++++++++ src/radeon_video.c | 32 +++++++++++++++++++++++++++++++- src/radeon_video.h | 5 +++++ 12 files changed, 151 insertions(+), 4 deletions(-) diff --git a/src/atombios_crtc.c b/src/atombios_crtc.c index 4e2395f..620bc8d 100644 --- a/src/atombios_crtc.c +++ b/src/atombios_crtc.c @@ -511,6 +511,10 @@ atombios_crtc_mode_set(xf86CrtcPtr crtc, else OUTREG(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); + + OUTREG(AVIVO_D1MODE_VLINE_START_END + radeon_crtc->crtc_offset, + ((0 << AVIVO_D1MODE_VLINE_START_SHIFT) | + (mode->VDisplay << AVIVO_D1MODE_VLINE_END_SHIFT))); } atombios_crtc_set_pll(crtc, adjusted_mode, pll_flags); diff --git a/src/legacy_crtc.c b/src/legacy_crtc.c index 75ab6c8..2e7063c 100644 --- a/src/legacy_crtc.c +++ b/src/legacy_crtc.c @@ -133,8 +133,10 @@ RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, OUTREG(RADEON_CRTC_V_TOTAL_DISP, restore->crtc_v_total_disp); OUTREG(RADEON_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid); + OUTREG(RADEON_CRTC_GUI_TRIG_VLINE, restore->crtc_gui_trig_vline); + if (IS_R300_VARIANT) - OUTREG(R300_CRTC_TILE_X0_Y0, restore->crtc_tile_x0_y0); + OUTREG(R300_CRTC_TILE_X0_Y0, restore->crtc_tile_x0_y0); OUTREG(RADEON_CRTC_OFFSET_CNTL, restore->crtc_offset_cntl); OUTREG(RADEON_CRTC_OFFSET, restore->crtc_offset); @@ -177,11 +179,13 @@ RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, OUTREG(RADEON_CRTC2_V_TOTAL_DISP, restore->crtc2_v_total_disp); OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid); + OUTREG(RADEON_CRTC2_GUI_TRIG_VLINE, restore->crtc2_gui_trig_vline); + OUTREG(RADEON_FP_H2_SYNC_STRT_WID, restore->fp_h2_sync_strt_wid); OUTREG(RADEON_FP_V2_SYNC_STRT_WID, restore->fp_v2_sync_strt_wid); if (IS_R300_VARIANT) - OUTREG(R300_CRTC2_TILE_X0_Y0, restore->crtc2_tile_x0_y0); + OUTREG(R300_CRTC2_TILE_X0_Y0, restore->crtc2_tile_x0_y0); OUTREG(RADEON_CRTC2_OFFSET_CNTL, restore->crtc2_offset_cntl); OUTREG(RADEON_CRTC2_OFFSET, restore->crtc2_offset); @@ -518,6 +522,8 @@ RADEONSaveCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) save->crtc_v_total_disp = INREG(RADEON_CRTC_V_TOTAL_DISP); save->crtc_v_sync_strt_wid = INREG(RADEON_CRTC_V_SYNC_STRT_WID); + save->crtc_gui_trig_vline = INREG(RADEON_CRTC_GUI_TRIG_VLINE); + save->crtc_offset = INREG(RADEON_CRTC_OFFSET); save->crtc_offset_cntl = INREG(RADEON_CRTC_OFFSET_CNTL); save->crtc_pitch = INREG(RADEON_CRTC_PITCH); @@ -553,6 +559,9 @@ RADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) save->crtc2_h_sync_strt_wid = INREG(RADEON_CRTC2_H_SYNC_STRT_WID); save->crtc2_v_total_disp = INREG(RADEON_CRTC2_V_TOTAL_DISP); save->crtc2_v_sync_strt_wid = INREG(RADEON_CRTC2_V_SYNC_STRT_WID); + + save->crtc2_gui_trig_vline = INREG(RADEON_CRTC2_GUI_TRIG_VLINE); + save->crtc2_offset = INREG(RADEON_CRTC2_OFFSET); save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL); save->crtc2_pitch = INREG(RADEON_CRTC2_PITCH); @@ -946,6 +955,9 @@ RADEONInitCrtcRegisters(xf86CrtcPtr crtc, RADEONSavePtr save, (pScrn->bitsPerPixel * 8)); save->crtc_pitch |= save->crtc_pitch << 16; + save->crtc_gui_trig_vline = ((0 << RADEON_CRTC_GUI_TRIG_VLINE_START_SHIFT) | + (mode->CrtcVDisplay << RADEON_CRTC_GUI_TRIG_VLINE_END_SHIFT)); + if (info->IsDellServer) { save->dac2_cntl = info->SavedReg->dac2_cntl; save->tv_dac_cntl = info->SavedReg->tv_dac_cntl; @@ -1137,6 +1149,9 @@ RADEONInitCrtc2Registers(xf86CrtcPtr crtc, RADEONSavePtr save, ((pScrn->bitsPerPixel * 8) -1)) / (pScrn->bitsPerPixel * 8); save->crtc2_pitch |= save->crtc2_pitch << 16; + save->crtc2_gui_trig_vline = ((0 << RADEON_CRTC_GUI_TRIG_VLINE_START_SHIFT) | + (mode->CrtcVDisplay << RADEON_CRTC_GUI_TRIG_VLINE_END_SHIFT)); + /* check to see if TV DAC is enabled for another crtc and keep it enabled */ if (save->crtc2_gen_cntl & RADEON_CRTC2_CRT2_ON) save->crtc2_gen_cntl = RADEON_CRTC2_CRT2_ON; diff --git a/src/radeon.h b/src/radeon.h index f7ae1a8..16ec6d4 100644 --- a/src/radeon.h +++ b/src/radeon.h @@ -938,8 +938,10 @@ extern Bool radeon_card_posted(ScrnInfoPtr pScrn); /* radeon_commonfuncs.c */ #ifdef XF86DRI extern void RADEONWaitForIdleCP(ScrnInfoPtr pScrn); +extern void RADEONWaitForVLineCP(ScrnInfoPtr pScrn, PixmapPtr pPix, int crtc); #endif extern void RADEONWaitForIdleMMIO(ScrnInfoPtr pScrn); +extern void RADEONWaitForVLineMMIO(ScrnInfoPtr pScrn, PixmapPtr pPix, int crtc); /* radeon_crtc.c */ extern void radeon_crtc_dpms(xf86CrtcPtr crtc, int mode); diff --git a/src/radeon_commonfuncs.c b/src/radeon_commonfuncs.c index dba197e..216178b 100644 --- a/src/radeon_commonfuncs.c +++ b/src/radeon_commonfuncs.c @@ -667,6 +667,39 @@ static void FUNC_NAME(RADEONInit3DEngine)(ScrnInfoPtr pScrn) } +/* inserts a wait for vline in the command stream */ +void FUNC_NAME(RADEONWaitForVLine)(ScrnInfoPtr pScrn, PixmapPtr pPix, int crtc) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + uint32_t offset; + ACCEL_PREAMBLE(); + + if ((crtc < 0) || (crtc > 1)) + return; + + if (!xf86_config->crtc[crtc]->enabled) + return; + +#ifdef USE_EXA + if (info->useEXA) + offset = exaGetPixmapOffset(pPix); + else +#endif + offset = pPix->devPrivate.ptr - info->FB; + + /* if drawing to front buffer */ + if (offset == 0) { + BEGIN_ACCEL(1); + if (crtc == 0) + OUT_ACCEL_REG(RADEON_WAIT_UNTIL, (RADEON_WAIT_FE_CRTC_VLINE | + RADEON_ENG_DISPLAY_SELECT_CRTC0)); + else + OUT_ACCEL_REG(RADEON_WAIT_UNTIL, (RADEON_WAIT_FE_CRTC_VLINE | + RADEON_ENG_DISPLAY_SELECT_CRTC1)); + FINISH_ACCEL(); + } +} /* MMIO: * diff --git a/src/radeon_exa.c b/src/radeon_exa.c index 0f86fdd..6b35d19 100644 --- a/src/radeon_exa.c +++ b/src/radeon_exa.c @@ -192,6 +192,33 @@ Bool RADEONGetPixmapOffsetPitch(PixmapPtr pPix, uint32_t *pitch_offset) return RADEONGetOffsetPitch(pPix, bpp, pitch_offset, offset, pitch); } +/* + * Used for vblank render stalling. + * Ideally we'd have one pixmap per crtc. + * syncing per-blit is unrealistic so, + * we sync to whichever crtc has a larger area. + */ +int RADEONBiggerCrtcArea(PixmapPtr pPix) +{ + ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int c, crtc_num = -1, area = 0; + + for (c = 0; c < xf86_config->num_crtc; c++) { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (!crtc->enabled) + continue; + + if ((crtc->mode.HDisplay * crtc->mode.VDisplay) > area) { + area = crtc->mode.HDisplay * crtc->mode.VDisplay; + crtc_num = c; + } + } + + return crtc_num; +} + #if X_BYTE_ORDER == X_BIG_ENDIAN static unsigned long swapper_surfaces[3]; diff --git a/src/radeon_exa_funcs.c b/src/radeon_exa_funcs.c index 62224d0..76d6c41 100644 --- a/src/radeon_exa_funcs.c +++ b/src/radeon_exa_funcs.c @@ -117,6 +117,8 @@ FUNC_NAME(RADEONPrepareSolid)(PixmapPtr pPix, int alu, Pixel pm, Pixel fg) OUT_ACCEL_REG(RADEON_DST_PITCH_OFFSET, dst_pitch_offset); FINISH_ACCEL(); + FUNC_NAME(RADEONWaitForVLine)(pScrn, pPix, RADEONBiggerCrtcArea(pPix)); + return TRUE; } @@ -205,6 +207,8 @@ FUNC_NAME(RADEONPrepareCopy)(PixmapPtr pSrc, PixmapPtr pDst, FUNC_NAME(RADEONDoPrepareCopy)(pScrn, src_pitch_offset, dst_pitch_offset, datatype, rop, planemask); + FUNC_NAME(RADEONWaitForVLine)(pScrn, pDst, RADEONBiggerCrtcArea(pDst)); + return TRUE; } @@ -264,7 +268,7 @@ FUNC_NAME(RADEONUploadToScreen)(PixmapPtr pDst, int x, int y, int w, int h, unsigned int hpass; uint32_t buf_pitch, dst_pitch_off; #endif -#if X_BYTE_ORDER == X_BIG_ENDIAN +#if X_BYTE_ORDER == X_BIG_ENDIAN unsigned char *RADEONMMIO = info->MMIO; unsigned int swapper = info->ModeReg->surface_cntl & ~(RADEON_NONSURF_AP0_SWP_32BPP | RADEON_NONSURF_AP1_SWP_32BPP | @@ -284,6 +288,9 @@ FUNC_NAME(RADEONUploadToScreen)(PixmapPtr pDst, int x, int y, int w, int h, ACCEL_PREAMBLE(); RADEON_SWITCH_TO_2D(); + + FUNC_NAME(RADEONWaitForVLine)(pScrn, pDst, RADEONBiggerCrtcArea(pDst)); + while ((buf = RADEONHostDataBlit(pScrn, cpp, w, dst_pitch_off, &buf_pitch, x, &y, (unsigned int*)&h, &hpass)) != 0) { diff --git a/src/radeon_exa_render.c b/src/radeon_exa_render.c index 97199ae..8b76424 100644 --- a/src/radeon_exa_render.c +++ b/src/radeon_exa_render.c @@ -624,6 +624,8 @@ static Bool FUNC_NAME(R100PrepareComposite)(int op, OUT_ACCEL_REG(RADEON_RB3D_BLENDCNTL, blendcntl); FINISH_ACCEL(); + FUNC_NAME(RADEONWaitForVLine)(pScrn, pDst, RADEONBiggerCrtcArea(pDst)); + return TRUE; } @@ -930,6 +932,8 @@ static Bool FUNC_NAME(R200PrepareComposite)(int op, PicturePtr pSrcPicture, OUT_ACCEL_REG(RADEON_RB3D_BLENDCNTL, blendcntl); FINISH_ACCEL(); + FUNC_NAME(RADEONWaitForVLine)(pScrn, pDst, RADEONBiggerCrtcArea(pDst)); + return TRUE; } @@ -1839,6 +1843,8 @@ static Bool FUNC_NAME(R300PrepareComposite)(int op, PicturePtr pSrcPicture, FINISH_ACCEL(); + FUNC_NAME(RADEONWaitForVLine)(pScrn, pDst, RADEONBiggerCrtcArea(pDst)); + return TRUE; } diff --git a/src/radeon_probe.h b/src/radeon_probe.h index c14241e..7ecfdb3 100644 --- a/src/radeon_probe.h +++ b/src/radeon_probe.h @@ -438,6 +438,7 @@ typedef struct { uint32_t crtc_h_sync_strt_wid; uint32_t crtc_v_total_disp; uint32_t crtc_v_sync_strt_wid; + uint32_t crtc_gui_trig_vline; uint32_t crtc_offset; uint32_t crtc_offset_cntl; uint32_t crtc_pitch; @@ -459,6 +460,7 @@ typedef struct { uint32_t crtc2_h_sync_strt_wid; uint32_t crtc2_v_total_disp; uint32_t crtc2_v_sync_strt_wid; + uint32_t crtc2_gui_trig_vline; uint32_t crtc2_offset; uint32_t crtc2_offset_cntl; uint32_t crtc2_pitch; diff --git a/src/radeon_reg.h b/src/radeon_reg.h index 19f9869..fc05efc 100644 --- a/src/radeon_reg.h +++ b/src/radeon_reg.h @@ -401,6 +401,9 @@ # define RADEON_CRTC_H_CUTOFF_ACTIVE_EN (1<<4) # define RADEON_CRTC_V_CUTOFF_ACTIVE_EN (1<<5) #define RADEON_CRTC_GUI_TRIG_VLINE 0x0218 +# define RADEON_CRTC_GUI_TRIG_VLINE_START_SHIFT 0 +# define RADEON_CRTC_GUI_TRIG_VLINE_END_SHIFT 16 +# define RADEON_CRTC_GUI_TRIG_VLINE_INV (1 << 15) #define RADEON_CRTC_H_SYNC_STRT_WID 0x0204 # define RADEON_CRTC_H_SYNC_STRT_PIX (0x07 << 0) # define RADEON_CRTC_H_SYNC_STRT_CHAR (0x3ff << 3) @@ -3629,6 +3632,11 @@ #define AVIVO_D1SCL_UPDATE 0x65cc # define AVIVO_D1SCL_UPDATE_LOCK (1<<16) +#define AVIVO_D1MODE_VLINE_START_END 0x6538 +# define AVIVO_D1MODE_VLINE_START_SHIFT 0 +# define AVIVO_D1MODE_VLINE_END_SHIFT 16 +# define AVIVO_D1MODE_VLINE_INV (1 << 31) + /* second crtc */ #define AVIVO_D2CRTC_H_TOTAL 0x6800 #define AVIVO_D2CRTC_H_BLANK_START_END 0x6804 diff --git a/src/radeon_textured_videofuncs.c b/src/radeon_textured_videofuncs.c index c5ad0e1..5506c4b 100644 --- a/src/radeon_textured_videofuncs.c +++ b/src/radeon_textured_videofuncs.c @@ -1123,6 +1123,14 @@ FUNC_NAME(RADEONDisplayTexturedVideo)(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv } } + FUNC_NAME(RADEONWaitForVLine)(pScrn, pPixmap, + radeon_covering_crtc_num(pScrn, + pPriv->drw_x, + pPriv->drw_x + pPriv->dst_w, + pPriv->drw_y, + pPriv->drw_y + pPriv->dst_h, + pPriv->desired_crtc)); + while (nBox--) { int srcX, srcY, srcw, srch; int dstX, dstY, dstw, dsth; diff --git a/src/radeon_video.c b/src/radeon_video.c index 6249cea..423ea28 100644 --- a/src/radeon_video.c +++ b/src/radeon_video.c @@ -105,7 +105,6 @@ static Atom xvOvAlpha, xvGrAlpha, xvAlphaMode; #define GET_PORT_PRIVATE(pScrn) \ (RADEONPortPrivPtr)((RADEONPTR(pScrn))->adaptor->pPortPrivates[0].ptr) -#ifndef HAVE_XF86CRTCCLIPVIDEOHELPER static void radeon_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) { @@ -136,6 +135,37 @@ radeon_box_area(BoxPtr box) return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); } +int +radeon_covering_crtc_num(ScrnInfoPtr pScrn, + int x1, int x2, int y1, int y2, + xf86CrtcPtr desired) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int coverage, best_coverage; + int c, best_crtc = 0; + BoxRec box, crtc_box, cover_box; + + box.x1 = x1; + box.x2 = x2; + box.y1 = y1; + box.y2 = y2; + best_coverage = 0; + for (c = 0; c < xf86_config->num_crtc; c++) { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + radeon_crtc_box(crtc, &crtc_box); + radeon_box_intersect(&cover_box, &crtc_box, &box); + coverage = radeon_box_area(&cover_box); + if (coverage && crtc == desired) { + return c; + } else if (coverage > best_coverage) { + best_crtc = c; + best_coverage = coverage; + } + } + return best_crtc; +} + +#ifndef HAVE_XF86CRTCCLIPVIDEOHELPER static xf86CrtcPtr radeon_covering_crtc(ScrnInfoPtr pScrn, BoxPtr box, diff --git a/src/radeon_video.h b/src/radeon_video.h index 11b8029..a08e4e3 100644 --- a/src/radeon_video.h +++ b/src/radeon_video.h @@ -113,6 +113,11 @@ typedef struct { int drw_x, drw_y; } RADEONPortPrivRec, *RADEONPortPrivPtr; +int +radeon_covering_crtc_num(ScrnInfoPtr pScrn, + int x1, int x2, int y1, int y2, + xf86CrtcPtr desired); + void RADEONInitI2C(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv); void RADEONResetI2C(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv); -- 1.6.0.2