summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hilber <sparkie@lowbyte.de>2008-08-08 08:00:00 +0000
committerPaul Menzel <paulepanter@users.sourceforge.net>2009-06-06 13:47:52 +0200
commit8cdd8d457213440325006316a7a39f640337b39a (patch)
treee64adc2938d32a3a3afaea21953557b1594ffdb6
parent79b36083b7c19115ba6397af4d9a8dd04ee2065b (diff)
downloadxf86-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.c10
-rw-r--r--src/radeon_video.c207
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
}