Attached are some patches that improve field parity and triple buffering
in the matrox driver.
I've moved the buffer flipping completely to the kernel which should make
it less probable that the hardware flips the buffers when we're not
looking. The other major benefit is that field parity no longer causes the
Flip() call to block. The application will continue without further
delays. This is especially nice with mplayer since it's single threaded.
The field parity part is obviously for CRTC2 but the patch makes triple
buffering more robust on BES too.
One patch is for matroxfb obviously and one for DirectFB.
The third patch is for mplayer and it makes dfbmga use the field parity
information from the codec. That should make it possible to watch
soft-telecined stuff on the TV with near perfect field order.
Oh and if you try this use CVS DirectFB since there was a problem with
dynamic field parity changes. I fixed it yeasterday (or was it the day
before that). Anyways everyone who likes this field parity stuff should
definately try these patches ;)
--
Ville Syrjälä
[EMAIL PROTECTED]
http://www.sci.fi/~syrjala/
diff -urN matrox.6/matroxfb_base.c matrox/matroxfb_base.c
--- matrox.6/matroxfb_base.c 2005-10-26 00:29:13.000000000 +0300
+++ matrox/matroxfb_base.c 2005-10-26 00:52:39.000000000 +0300
@@ -122,6 +122,7 @@
#endif
static void matroxfb_unregister_device(struct matrox_fb_info* minfo);
+static void matroxfb_set_address(WPMINFO struct matrox_address *address);
/* --------------------------------------------------------------------- */
@@ -218,6 +219,12 @@
if (status & 0x200) {
mga_outl(M_ICLEAR, 0x200);
ACCESS_FBINFO(crtc2.vsync.cnt)++;
+ ACCESS_FBINFO(crtc2.vsync.field) = (mga_inl(0x3C48) >> 24) & 1;
+ if (ACCESS_FBINFO(crtc2.pan) &&
+ ACCESS_FBINFO(crtc2.address.field) !=
ACCESS_FBINFO(crtc2.vsync.field)) {
+ ACCESS_FBINFO(crtc2.pan) = 0;
+ matroxfb_set_address(PMINFO
&ACCESS_FBINFO(crtc2.address));
+ }
wake_up_interruptible(&ACCESS_FBINFO(crtc2.vsync.wait));
handled = 1;
}
@@ -300,6 +307,71 @@
return 0;
}
+static void matroxfb_set_address(WPMINFO struct matrox_address *address)
+{
+ switch (address->device) {
+ case MATROX_ADDRESS_DEVICE_BES:
+ mga_outl(0x3D00, address->offset[0]);
+ mga_outl(0x3D04, address->offset[1]);
+ mga_outl(0x3D10, address->offset[2]);
+ mga_outl(0x3D14, address->offset[3]);
+ if (ACCESS_FBINFO(devflags.accelerator) ==
FB_ACCEL_MATROX_MGAG400) {
+ mga_outl(0x3D60, address->offset[4]);
+ mga_outl(0x3D64, address->offset[5]);
+ }
+ mga_inl(0x3D00);
+ break;
+ case MATROX_ADDRESS_DEVICE_CRTC2:
+ mga_outl(0x3C28, address->offset[0]);
+ mga_outl(0x3C2C, address->offset[1]);
+ mga_outl(0x3C30, address->offset[2]);
+ mga_outl(0x3C34, address->offset[3]);
+ mga_outl(0x3C38, address->offset[4]);
+ mga_outl(0x3C3C, address->offset[5]);
+ mga_inl(0x3C28);
+ break;
+ }
+}
+
+int matroxfb_address(WPMINFO struct matrox_address *address)
+{
+ if (address->device == MATROX_ADDRESS_DEVICE_CRTC2 &&
+ ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
+ int vbl;
+
+ /* Interrupts are always needed to update vsync.cnt. */
+ vbl = !matroxfb_enable_irq(PMINFO 0) && address->field ==
ACCESS_FBINFO(crtc2.vsync.field);
+
+ if (vbl) {
+ ACCESS_FBINFO(crtc2.address) = *address;
+ ACCESS_FBINFO(crtc2.pan) = 1;
+ } else {
+ ACCESS_FBINFO(crtc2.pan) = 0;
+ matroxfb_set_address(PMINFO address);
+ }
+
+ address->field = ACCESS_FBINFO(crtc2.vsync.field);
+ address->count = ACCESS_FBINFO(crtc2.vsync.cnt);
+
+ return 0;
+ } else if (address->device == MATROX_ADDRESS_DEVICE_BES &&
+ (ACCESS_FBINFO(devflags.accelerator) ==
FB_ACCEL_MATROX_MGAG400 ||
+ ACCESS_FBINFO(devflags.accelerator) ==
FB_ACCEL_MATROX_MGAG200)) {
+
+ /* Interrupts are always needed to update vsync.cnt. */
+ matroxfb_enable_irq(PMINFO 0);
+
+ matroxfb_set_address(PMINFO address);
+
+ address->field = -1; /* N/A */
+ address->count = ACCESS_FBINFO(crtc1.vsync.cnt);
+
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
/* --------------------------------------------------------------------- */
static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
@@ -868,6 +940,8 @@
.name = "Panellink output",
};
+#define MATROXFB_ADDRESS _IOWR('n', 0xFC, struct matrox_address)
+
static int matroxfb_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
struct fb_info *info)
@@ -1161,6 +1235,23 @@
up_read(&ACCESS_FBINFO(altout).lock);
return err;
}
+ case MATROXFB_ADDRESS:
+ {
+ struct matrox_address address;
+ int err;
+
+ if (copy_from_user(&address, argp,
sizeof(address)))
+ return -EFAULT;
+
+ err = matroxfb_address(PMINFO &address);
+ if (err)
+ return err;
+
+ if (copy_to_user(argp, &address,
sizeof(address)))
+ return -EFAULT;
+
+ return 0;
+ }
}
return -ENOTTY;
}
diff -urN matrox.6/matroxfb_base.h matrox/matroxfb_base.h
--- matrox.6/matroxfb_base.h 2005-10-26 00:29:13.000000000 +0300
+++ matrox/matroxfb_base.h 2005-10-26 01:16:59.000000000 +0300
@@ -364,6 +364,17 @@
struct matrox_vsync {
wait_queue_head_t wait;
unsigned int cnt;
+ unsigned int field;
+};
+
+#define MATROX_ADDRESS_DEVICE_CRTC1 0
+#define MATROX_ADDRESS_DEVICE_BES 1
+#define MATROX_ADDRESS_DEVICE_CRTC2 2
+struct matrox_address {
+ u32 device;
+ u32 field;
+ u32 count;
+ u32 offset[6];
};
struct matrox_fb_info {
@@ -397,6 +408,8 @@
int mnp;
struct matroxfb_dh_fb_info* info;
struct rw_semaphore lock;
+ int pan;
+ struct matrox_address address;
} crtc2;
struct {
struct rw_semaphore lock;
Index: matrox.h
===================================================================
RCS file: /cvs/directfb/DirectFB/gfxdrivers/matrox/matrox.h,v
retrieving revision 1.38
diff -u -r1.38 matrox.h
--- matrox.h 26 Oct 2005 06:33:46 -0000 1.38
+++ matrox.h 27 Oct 2005 16:39:59 -0000
@@ -149,4 +149,16 @@
return ret;
}
+#define MATROX_ADDRESS_DEVICE_CRTC1 0
+#define MATROX_ADDRESS_DEVICE_BES 1
+#define MATROX_ADDRESS_DEVICE_CRTC2 2
+struct matrox_address
+{
+ __u32 device;
+ __u32 field;
+ __u32 count;
+ __u32 offset[6];
+};
+#define MATROXFB_ADDRESS _IOWR('n', 0xFC, struct matrox_address)
+
#endif
Index: matrox_bes.c
===================================================================
RCS file: /cvs/directfb/DirectFB/gfxdrivers/matrox/matrox_bes.c,v
retrieving revision 1.58
diff -u -r1.58 matrox_bes.c
--- matrox_bes.c 26 Oct 2005 07:23:16 -0000 1.58
+++ matrox_bes.c 27 Oct 2005 16:40:00 -0000
@@ -54,6 +54,7 @@
#include <direct/mem.h>
+#include <fbdev/fbdev.h>
#include "regs.h"
#include "mmio.h"
@@ -61,6 +62,7 @@
typedef struct {
CoreLayerRegionConfig config;
+ __u32 last_count;
/* Stored registers */
struct {
@@ -260,6 +262,8 @@
{
bes_calc_regs( mdrv, mbes, config, surface );
bes_set_regs( mdrv, mbes, true );
+
+ mbes->last_count = 0;
}
/* set color key */
@@ -316,10 +320,36 @@
MatroxDriverData *mdrv = (MatroxDriverData*) driver_data;
MatroxBesLayerData *mbes = (MatroxBesLayerData*) layer_data;
+#if 0
bes_calc_regs( mdrv, mbes, &mbes->config, surface );
bes_set_regs( mdrv, mbes, flags & DSFLIP_ONSYNC );
dfb_surface_flip_buffers( surface, false );
+#else
+ {
+ FBDev *dfb_fbdev = dfb_system_data();
+ struct matrox_address address;
+
+ bes_calc_regs( mdrv, mbes, &mbes->config, surface );
+
+ address.device = MATROX_ADDRESS_DEVICE_BES;
+ address.field = -1;
+ address.count = mbes->last_count + 1;
+ address.offset[0] = mbes->regs.besA1ORG;
+ address.offset[1] = mbes->regs.besA2ORG;
+ address.offset[2] = mbes->regs.besA1CORG;
+ address.offset[3] = mbes->regs.besA2CORG;
+ address.offset[4] = mbes->regs.besA1C3ORG;
+ address.offset[5] = mbes->regs.besA2C3ORG;
+
+ if (ioctl( dfb_fbdev->fd, MATROXFB_ADDRESS, &address ))
+ D_ERROR( "DirectFB/Matrox/BES Address ioctl() failed!\n" );
+
+ dfb_surface_flip_buffers( surface, address.count == mbes->last_count
);
+
+ mbes->last_count = address.count;
+ }
+#endif
if (flags & DSFLIP_WAIT)
dfb_screen_wait_vsync( mdrv->primary );
Index: matrox_crtc2.c
===================================================================
RCS file: /cvs/directfb/DirectFB/gfxdrivers/matrox/matrox_crtc2.c,v
retrieving revision 1.31
diff -u -r1.31 matrox_crtc2.c
--- matrox_crtc2.c 26 Oct 2005 07:26:16 -0000 1.31
+++ matrox_crtc2.c 27 Oct 2005 16:40:00 -0000
@@ -61,7 +61,10 @@
typedef struct {
CoreLayerRegionConfig config;
DFBColorAdjustment adj;
- int field;
+ __u32 parity;
+ __u32 last_parity;
+ __u32 last_field;
+ __u32 last_count;
/* Stored registers */
struct {
@@ -247,7 +250,7 @@
mcrtc2->config = *config;
if (updated & CLRCF_PARITY)
- mcrtc2->field = !config->parity;
+ mcrtc2->parity = !config->parity;
if (updated & (CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT |
CLRCF_SURFACE_CAPS | CLRCF_ALPHA_RAMP | CLRCF_SURFACE)) {
@@ -257,6 +260,10 @@
ret = crtc2_enable_output( mdrv, mcrtc2 );
if (ret)
return ret;
+
+ mcrtc2->last_parity = 1;
+ mcrtc2->last_field = 0;
+ mcrtc2->last_count = 0;
}
return DFB_OK;
@@ -286,6 +293,7 @@
{
MatroxDriverData *mdrv = (MatroxDriverData*) driver_data;
MatroxCrtc2LayerData *mcrtc2 = (MatroxCrtc2LayerData*) layer_data;
+#if 0
volatile __u8 *mmio = mdrv->mmio_base;
crtc2_calc_buffer( mdrv, mcrtc2, surface );
@@ -293,7 +301,7 @@
if (mcrtc2->config.options & DLOP_FIELD_PARITY) {
int field = (mga_in32( mmio, C2VCOUNT ) & C2FIELD) ? 1 : 0;
- while (field == mcrtc2->field) {
+ while (field == mcrtc2->parity) {
dfb_screen_wait_vsync( mdrv->secondary );
field = (mga_in32( mmio, C2VCOUNT ) & C2FIELD) ? 1 : 0;
@@ -302,6 +310,38 @@
crtc2_set_buffer( mdrv, mcrtc2 );
dfb_surface_flip_buffers( surface, false );
+#else
+ {
+ FBDev *dfb_fbdev = dfb_system_data();
+ struct matrox_address address;
+ __u32 diff;
+
+ crtc2_calc_buffer( mdrv, mcrtc2, surface );
+
+ address.device = MATROX_ADDRESS_DEVICE_CRTC2;
+ address.field = (mcrtc2->config.options & DLOP_FIELD_PARITY) ?
mcrtc2->parity : -1;
+ address.count = mcrtc2->last_count + 2;
+ address.offset[0] = mcrtc2->regs.c2STARTADD0;
+ address.offset[1] = mcrtc2->regs.c2STARTADD1;
+ address.offset[2] = mcrtc2->regs.c2PL2STARTADD0;
+ address.offset[3] = mcrtc2->regs.c2PL2STARTADD1;
+ address.offset[4] = mcrtc2->regs.c2PL3STARTADD0;
+ address.offset[5] = mcrtc2->regs.c2PL3STARTADD1;
+
+ if (ioctl( dfb_fbdev->fd, MATROXFB_ADDRESS, &address ))
+ D_ERROR( "DirectFB/Matrox/CRTC2 Address ioctl() failed!\n" );
+
+ diff = address.count >= mcrtc2->last_count ?
+ address.count - mcrtc2->last_count :
+ 0xFFFFFFFF - mcrtc2->last_count + address.count;
+
+ dfb_surface_flip_buffers( surface, diff == 0 || (diff == 1 &&
mcrtc2->last_field == mcrtc2->last_parity) );
+
+ mcrtc2->last_count = address.count;
+ mcrtc2->last_field = address.field;
+ mcrtc2->last_parity = (mcrtc2->config.options & DLOP_FIELD_PARITY) ?
mcrtc2->parity : !address.field;
+ }
+#endif
if (flags & DSFLIP_WAIT)
dfb_screen_wait_vsync( mdrv->secondary );
Index: libvo/vo_dfbmga.c
===================================================================
RCS file: /cvsroot/mplayer/main/libvo/vo_dfbmga.c,v
retrieving revision 1.29
diff -u -r1.29 vo_dfbmga.c
--- libvo/vo_dfbmga.c 26 Oct 2005 07:41:41 -0000 1.29
+++ libvo/vo_dfbmga.c 26 Oct 2005 07:44:57 -0000
@@ -106,6 +106,8 @@
static int is_g200;
+static int top_field_first;
+
/******************************
* vo_dfbmga *
******************************/
@@ -313,6 +315,9 @@
} else if (!strncmp(vo_subdevice, "bottom", 6)) {
field_parity = 1;
vo_subdevice += 6;
+ } else if (!strncmp(vo_subdevice, "auto", 4)) {
+ field_parity = 2;
+ vo_subdevice += 4;
} else {
show_help = 1;
break;
@@ -372,9 +377,10 @@
" single Use single buffering\n"
" double Use double buffering\n"
" triple Use triple buffering\n"
- " fieldparity=(top|bottom)\n"
+ " fieldparity=(top|bottom|auto)\n"
" top Top field first\n"
" bottom Bottom field first\n"
+ " auto Automatic\n"
" tvnorm=(pal|ntsc|auto)\n"
" pal Force PAL\n"
" ntsc Force NTSC\n"
@@ -712,6 +718,9 @@
case 1:
mp_msg( MSGT_VO, MSGL_INFO, "Bottom field first\n");
break;
+ case 2:
+ mp_msg( MSGT_VO, MSGL_INFO, "Automatic\n");
+ break;
}
switch (dlc.pixelformat) {
@@ -745,7 +754,7 @@
}
#if DIRECTFBVERSION > 916
- if (field_parity != -1)
+ if (field_parity == 0 || field_parity == 1)
crtc2->SetFieldParity( crtc2, field_parity );
#endif
@@ -1165,9 +1174,13 @@
blit_to_screen();
if (flipping) {
- if (use_crtc2)
+ if (use_crtc2) {
+#if DIRECTFBVERSION > 916
+ if (field_parity == 2)
+ crtc2->SetFieldParity( crtc2, !top_field_first );
+#endif
c2frame->Flip( c2frame, NULL, vo_vsync ? DSFLIP_WAITFORSYNC :
DSFLIP_ONSYNC );
- else
+ } else
besframe->Flip( besframe, NULL, vo_vsync ? DSFLIP_WAITFORSYNC :
DSFLIP_ONSYNC );
if (!use_spic) {
@@ -1284,6 +1297,8 @@
static uint32_t
draw_image( mp_image_t *mpi )
{
+ top_field_first = mpi->fields & MP_IMGFIELD_TOP_FIRST;
+
if (mpi->flags & MP_IMGFLAG_DIRECT) {
current_buf = (int) mpi->priv;
return VO_TRUE;
_______________________________________________
directfb-dev mailing list
[email protected]
http://mail.directfb.org/cgi-bin/mailman/listinfo/directfb-dev