diff options
author | Thomas Hilber <sparkie@lowbyte.de> | 2008-08-08 08:00:00 +0000 |
---|---|---|
committer | Paul Menzel <paulepanter@users.sourceforge.net> | 2009-06-06 13:47:52 +0200 |
commit | 8cdd8d457213440325006316a7a39f640337b39a (patch) | |
tree | e64adc2938d32a3a3afaea21953557b1594ffdb6 | |
parent | 79b36083b7c19115ba6397af4d9a8dd04ee2065b (diff) | |
download | xf86-video-ati-frc-8cdd8d457213440325006316a7a39f640337b39a.tar.gz xf86-video-ati-frc-8cdd8d457213440325006316a7a39f640337b39a.tar.bz2 |
Add frame rate conrol.
- reworked everything from scratch
- first approach to implement a PLL in software to lock VGA frame rate
to an external signal source (e.g. DVB stream frame rate)
- fixed scaler bug in RADEONDisplayVideo() (Thanks to Roland Scheidegger)
- found a way how to detect initial field parity on RADEON cards
- added patches from various sources to fix bugs in current
CVS xf86-video-ati (Thanks to Andy Burns)
- successfully tested on various mainboards and ATI RADEON type graphics car
including RV100/Radeon 7000 and Asus Pundit ID-3 (RS300/Radeon 9100 IGP)
Signed-off-by: Thomas Hilber <sparkie@lowbyte.de>
Signed-off-by: Paul Menzel <paulepanter@users.sourceforge.net>
-rw-r--r-- | src/legacy_crtc.c | 10 | ||||
-rw-r--r-- | src/radeon_video.c | 207 |
2 files changed, 212 insertions, 5 deletions
diff --git a/src/legacy_crtc.c b/src/legacy_crtc.c index f7216f9..2c35498 100644 --- a/src/legacy_crtc.c +++ b/src/legacy_crtc.c @@ -872,6 +872,7 @@ RADEONInitCrtcRegisters(xf86CrtcPtr crtc, RADEONSavePtr save, int hsync_start; int hsync_wid; int vsync_wid; + int fix_inter; switch (info->CurrentLayout.pixel_code) { case 4: format = 1; break; @@ -923,14 +924,17 @@ RADEONInitCrtcRegisters(xf86CrtcPtr crtc, RADEONSavePtr save, ? RADEON_CRTC_H_SYNC_POL : 0)); + /* fixup for interlaced modes */ + fix_inter = (mode->Flags & V_INTERLACE) ? 2 : 1; + /* This works for double scan mode. */ - save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) - | ((mode->CrtcVDisplay - 1) << 16)); + save->crtc_v_total_disp = (((mode->CrtcVTotal * fix_inter - 1) & 0xffff) + | ((mode->CrtcVDisplay * fix_inter - 1) << 16)); vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; if (!vsync_wid) vsync_wid = 1; - save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) + save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart * fix_inter - 1) & 0xfff) | ((vsync_wid & 0x1f) << 16) | ((mode->Flags & V_NVSYNC) ? RADEON_CRTC_V_SYNC_POL diff --git a/src/radeon_video.c b/src/radeon_video.c index ac60166..c72e131 100644 --- a/src/radeon_video.c +++ b/src/radeon_video.c @@ -8,6 +8,16 @@ #include <stdio.h> #include <math.h> +#define SYNC_FIELDS + +#ifdef SYNC_FIELDS +#define _RADEON_COMMON_H_ +#include <errno.h> +#include <sys/ioctl.h> +#include <xf86drm.h> +#include <drm/radeon_drm.h> +#endif + #include "radeon.h" #include "radeon_reg.h" #include "radeon_macros.h" @@ -275,6 +285,14 @@ void RADEONInitVideo(ScreenPtr pScreen) memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr)); adaptors = newAdaptors; +#define ENABLE_XV_OVERLAY_ADAPTOR + +/* + * enable this if you either want to use + * - recent xine-lib versions that let choose you adaptor type by configuration + * - XV overlay adaptor type + */ +#ifdef ENABLE_XV_OVERLAY_ADAPTOR if (!IS_AVIVO_VARIANT) { overlayAdaptor = RADEONSetupImageVideo(pScreen); if (overlayAdaptor != NULL) { @@ -284,7 +302,9 @@ void RADEONInitVideo(ScreenPtr pScreen) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set up overlay video\n"); RADEONInitOffscreenImages(pScreen); } - +#else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "XV overlay adaptor disabled by #define\n"); +#endif if (info->ChipFamily != CHIP_FAMILY_RV250) { if ((info->ChipFamily < CHIP_FAMILY_RS400) #ifdef XF86DRI @@ -2859,7 +2879,7 @@ RADEONDisplayVideo( OUTREG(RADEON_OV0_P23_V_ACCUM_INIT, p23_v_accum_init); OUTREG(RADEON_OV0_P23_H_ACCUM_INIT, p23_h_accum_init); - scale_cntl = RADEON_SCALER_ADAPTIVE_DEINT | RADEON_SCALER_DOUBLE_BUFFER + scale_cntl = RADEON_SCALER_VERT_PICK_NEAREST | RADEON_SCALER_ADAPTIVE_DEINT | RADEON_SCALER_DOUBLE_BUFFER | RADEON_SCALER_ENABLE | RADEON_SCALER_SMART_SWITCH | (0x7f<<16) | scaler_src; switch(id){ case FOURCC_UYVY: @@ -2893,6 +2913,189 @@ RADEONDisplayVideo( OUTREG(RADEON_OV0_SCALE_CNTL, scale_cntl); OUTREG(RADEON_OV0_REG_LOAD_CNTL, 0); + +#ifdef SYNC_FIELDS + +/* + * prefilter to prevent stray updates. + * our software PLL will not try to lock for these. + */ +#define SYNC_FRAME_CYCLE 40000 +#define SYNC_FIELD_CYCLE 20000 +#define SYNC_CATCH_RANGE 10000 + +/* --8<-- */ +/* + * we average 25 frames to yield a cycle time of + * about one second for analysis of frame rate data. + * this serves as frequency divider for our software PLL. + */ +#ifdef STANDALONE +#define SYNC_PLL_DIVIDER 1 +#else +#define SYNC_PLL_DIVIDER 25 +#endif + +/* + * offset in usecs from double buffer switch where we try to place double + * buffer updates. + * this lowers sensivity to jitter of our software PLL phase comparator. + */ +#define SYNC_POINT 10000 + +/* + * one trim increment compensates drift speed for about 29usec/sec. + * this represents resolution of our VCO input. + */ +#define VBL_MIN_STEP_USEC 29 + +/* NOT CURRENTLY USED + * to allow for smooth adaption also on slower devices we delimit maximum + * trim change per step size. + * this implements some kind of low pass filter for our VCO input. + */ +#define VBL_MAX_TRIM_REL 1000 + +/* + * maximum absolute trim values allowed due to current + * hardware/driver contraints. + * this delimits 'maximum voltage' being fed into our software PLL. + */ +#define VBL_MAX_TRIM_ABS 37 +#define VBL_MIN_TRIM_ABS 27 +#define VBL_RSYNC_FPOLAR 80 + +/* + * field polarity correction is clearly a task of the calling layer + * but for the moment we want to provide an all-in-one solution + * + * METHOD1 (fast): + * tries to resynchronize field polarity in one fell swoop + * by heavily incrementing the frame rate for a moment. + * this effectively drops a field. + * + * METHOD2 (slow): + * continuously increments frame rate until a field + * has been skipped. + * + * at most one of both methods is allowed at any time + */ +#define RESYNC_FIELD_POLARITY_METHOD1 +//#define RESYNC_FIELD_POLARITY_METHOD2 + +//#define DEBUG +#ifdef DEBUG +#define ERRORF ErrorF +#else +#define ERRORF(...) +#endif + +#ifdef STANDALONE +#define ErrorF printf +#define B(a) (*(argv + (a)) ? *(argv + (a)) : 0) +#else +#define B(a) (a) +#endif +/* --8<-- */ + +{ + static int fd; + static int cnt; + static int ds_usecs; + static int sync_point_disp; + static struct timeval skew_prev; + static drm_radeon_vsync_t vsync_prev; + drm_radeon_vsync_t vsync; + drm_radeon_setparam_t vbl_activate; + struct timeval filter; + struct timeval skew; + struct timeval drift_speed; + int tmp; + + if (!fd) { + if ((fd = drmOpen("radeon", 0)) < 0) { + ErrorF("drmOpen: %s\n", strerror(errno)); + } + vbl_activate.param = RADEON_SETPARAM_VBLANK_CRTC; + vbl_activate.value = DRM_RADEON_VBLANK_CRTC1; + if (ioctl(fd, DRM_IOCTL_RADEON_SETPARAM, &vbl_activate)) { + ErrorF("DRM_IOCTL_RADEON_SETPARAM: %s\n", strerror(errno)); + } + } + vsync.trim = 0; + if (ioctl(fd, DRM_IOCTL_RADEON_VSYNC, &vsync)) { + ErrorF("DRM_IOCTL_RADEON_VSYNC: %s\n", strerror(errno)); + } + VBL_SUB(vsync.tv_now, vsync_prev.tv_now, filter); + if (filter.tv_sec + || filter.tv_usec > SYNC_FRAME_CYCLE + SYNC_CATCH_RANGE + || filter.tv_usec < SYNC_FRAME_CYCLE - SYNC_CATCH_RANGE) { + + /* + * toss stray intervals and reset + */ + cnt = 0; + ds_usecs = 0; + sync_point_disp = 0; + skew_prev.tv_sec = ~0; + + ERRORF("RESET STRAY\n"); + } else { + +/* --8<-- */ +#ifdef RESYNC_FIELD_POLARITY_METHOD1 + if (vsync.vbls & 1 && B(1)) { + ErrorF(" <- resyncing field polarity M1 ->\n"); + vsync.trim = VBL_TEMPLATE | VBL_SET_TRIM | VBL_DEC_RATE | VBL_RSYNC_FPOLAR; + if (ioctl(fd, DRM_IOCTL_RADEON_VSYNC, &vsync)) { + ErrorF("DRM_IOCTL_RADEON_VSYNC: %s\n", strerror(errno)); exit(-1); + } + VBL_SUB(vsync.tv_now, vsync.tv_vbl, skew); + } else { +#endif + VBL_SUB(vsync.tv_now, vsync.tv_vbl, skew) + sync_point_disp += skew.tv_usec - SYNC_POINT; + if (skew_prev.tv_sec != ~0) { + VBL_SUB(skew, skew_prev, drift_speed); + VBL_TV2USEC(drift_speed, tmp); + ds_usecs += tmp; + } + if (!(cnt++ % SYNC_PLL_DIVIDER) && skew_prev.tv_sec != ~0) { + sync_point_disp /= SYNC_PLL_DIVIDER; +#ifdef RESYNC_FIELD_POLARITY_METHOD2 + if (vsync.vbls & 1 && B(1)) { + ErrorF(" <- resyncing field polarity M2 ->\n"); + sync_point_disp = sync_point_disp < 0 ? SYNC_POINT : -SYNC_POINT; + } +#endif + ErrorF("sync point displacement: %10d\n", sync_point_disp); + ErrorF("drift speed: %10d %s\n", ds_usecs, abs(ds_usecs) > 10000 ? "excessive drift speed" : ""); + if (B(1)) { + int trim = (ds_usecs + sync_point_disp) / VBL_MIN_STEP_USEC; + ErrorF("overall compensation: %10d %s\n", trim, abs(trim) <= 1 ? "completed" : ""); + trim = max(trim, -VBL_MAX_TRIM_REL); + trim = min(trim, VBL_MAX_TRIM_REL); + trim += (vsync.trim & 0xff) * (vsync.trim & VBL_INC_RATE ? -1 : 1); + trim = max(trim, -VBL_MIN_TRIM_ABS); + trim = min(trim, VBL_MAX_TRIM_ABS); + vsync.trim = VBL_TEMPLATE | VBL_SET_TRIM | (trim >= 0 ? VBL_DEC_RATE | trim : VBL_INC_RATE | -trim); + if (ioctl(fd, DRM_IOCTL_RADEON_VSYNC, &vsync)) { + ErrorF("DRM_IOCTL_RADEON_VSYNC: %s\n", strerror(errno)); exit(-1); + } + } + sync_point_disp = 0; + ds_usecs = 0; + } +#ifdef RESYNC_FIELD_POLARITY_METHOD1 + } +#endif + skew_prev = skew; +/* --8<-- */ + + } + vsync_prev = vsync; +} +#endif } |