I'm sure everyone remembers Brian's CRTC2 troubles. Well I think we
managed to fix it off list some time ago. The problem was caused by
displaying the fields in the wrong order.
Here's a patch with the solution I came up with. It adds a new method
IDirectFBDisplayLayer::SetFieldParity() to select which field is displayed
first after a Flip(). This behaviour isn't always the best choice so I
added {DLCAPS,DLOP}_FIELD_PARITY flags.
Is the term "field parity" correctly used here? I'm not very well informed
on video terminology.
My first implementation used IDirectFBSurface::SetField() for this but I
think it's better to have a private method for this. Or is it?
Should IDirectFBDisplayLayer::WaitForSync respect this too?
Any other (ir)relevant ideas?
PS.
I've also included a patch to mplayer to make use of this. Just use -vo
dfbmga:fieldparity=0 or 1 to select top field first or bottom field first
respectively.
--
Ville Syrj�l�
[EMAIL PROTECTED]
http://www.sci.fi/~syrjala/
diff -urN DirectFB/gfxdrivers/matrox/matrox_crtc2.c
DirectFB/gfxdrivers/matrox/matrox_crtc2.c
--- DirectFB/gfxdrivers/matrox/matrox_crtc2.c Fri Dec 27 19:50:08 2002
+++ DirectFB/gfxdrivers/matrox/matrox_crtc2.c Thu Feb 13 07:09:32 2003
@@ -57,6 +57,7 @@
DFBDisplayLayerConfig config;
DFBColorAdjustment adj;
int enabled;
+ int field;
/* Stored registers */
struct {
@@ -86,13 +87,15 @@
static void crtc2_set_regs( MatroxDriverData *mdrv, MatroxCrtc2LayerData *mcrtc2 );
static void crtc2_calc_regs( MatroxDriverData *mdrv, MatroxCrtc2LayerData *mcrtc2,
DisplayLayer *layer );
+static void crtc2_calc_buffer( MatroxDriverData *mdrv, MatroxCrtc2LayerData *mcrtc2,
+ DisplayLayer *layer );
static void crtc2_set_buffer( MatroxDriverData *mdrv, MatroxCrtc2LayerData *mcrtc2,
DisplayLayer *layer );
static DFBResult crtc2_disable_output( MatroxDriverData *mdrv, MatroxCrtc2LayerData
*mcrtc2 );
static DFBResult crtc2_enable_output( MatroxDriverData *mdrv, MatroxCrtc2LayerData
*mcrtc2,
DisplayLayer *layer );
-#define CRTC2_SUPPORTED_OPTIONS (DLOP_DEINTERLACING | DLOP_FLICKER_FILTERING)
+#define CRTC2_SUPPORTED_OPTIONS (DLOP_FIELD_PARITY | DLOP_FLICKER_FILTERING)
/**********************/
@@ -123,7 +126,7 @@
/* set capabilities and type */
layer_info->desc.caps = DLCAPS_SURFACE |
- DLCAPS_DEINTERLACING | DLCAPS_FLICKER_FILTERING |
+ DLCAPS_FIELD_PARITY | DLCAPS_FLICKER_FILTERING |
DLCAPS_BRIGHTNESS | DLCAPS_CONTRAST |
DLCAPS_HUE | DLCAPS_SATURATION;
layer_info->desc.type = DLTF_GRAPHICS | DLTF_VIDEO | DLTF_STILL_PICTURE;
@@ -264,12 +267,32 @@
MatroxDriverData *mdrv = (MatroxDriverData*) driver_data;
MatroxCrtc2LayerData *mcrtc2 = (MatroxCrtc2LayerData*) layer_data;
CoreSurface *surface = dfb_layer_surface( layer );
+ volatile __u8 *mmio = mdrv->mmio_base;
+
+ int vdisplay = (dfb_config->matrox_ntsc ? 480/2 : 576/2) + 2;
+ int line;
dfb_surface_flip_buffers( surface );
+ crtc2_calc_buffer( mdrv, mcrtc2, layer );
if (!mcrtc2->enabled)
return DFB_OK;
+ dfb_gfxcard_sync();
+
+ line = mga_in32( mmio, C2VCOUNT ) & 0x00000FFF;
+ if (line + 6 > vdisplay && line < vdisplay)
+ while ((mga_in32( mmio, C2VCOUNT ) & 0x00000FFF) != vdisplay)
+ ;
+
+ if (mcrtc2->config.options & DLOP_FIELD_PARITY) {
+ int field = (mga_in32( mmio, C2VCOUNT ) >> 24) & 0x1;
+
+ while (field == mcrtc2->field) {
+ crtc2_wait_vsync( mdrv );
+ field = (mga_in32( mmio, C2VCOUNT ) >> 24) & 0x1;
+ }
+ }
crtc2_set_buffer( mdrv, mcrtc2, layer );
if (flags & DSFLIP_WAITFORSYNC)
@@ -354,6 +377,18 @@
return DFB_OK;
}
+static DFBResult
+crtc2SetFieldParity( DisplayLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ int field )
+{
+ MatroxCrtc2LayerData *mcrtc2 = (MatroxCrtc2LayerData*) layer_data;
+
+ mcrtc2->field = field;
+
+ return DFB_OK;
+}
static DFBResult
crtc2WaitVSync( DisplayLayer *layer,
@@ -380,6 +415,7 @@
SetColorAdjustment: crtc2SetColorAdjustment,
SetOpacity: crtc2SetOpacity,
GetCurrentOutputField: crtc2GetCurrentOutputField,
+ SetFieldParity: crtc2SetFieldParity,
WaitVSync: crtc2WaitVSync
};
@@ -530,15 +566,12 @@
}
}
-static void crtc2_set_buffer( MatroxDriverData *mdrv,
- MatroxCrtc2LayerData *mcrtc2,
- DisplayLayer *layer )
+static void crtc2_calc_buffer( MatroxDriverData *mdrv,
+ MatroxCrtc2LayerData *mcrtc2,
+ DisplayLayer *layer )
{
CoreSurface *surface = dfb_layer_surface( layer );
SurfaceBuffer *front_buffer = surface->front_buffer;
- volatile __u8 *mmio = mdrv->mmio_base;
- int vdisplay = (dfb_config->matrox_ntsc ? 480/2 : 576/2) + 2;
- int line;
mcrtc2->regs.c2STARTADD1 = front_buffer->video.offset;
mcrtc2->regs.c2STARTADD0 = front_buffer->video.offset +
front_buffer->video.pitch;
@@ -561,13 +594,13 @@
default:
break;
}
+}
- dfb_gfxcard_sync();
-
- line = mga_in32( mmio, C2VCOUNT ) & 0x00000FFF;
- if (line + 6 > vdisplay && line < vdisplay)
- while ((mga_in32( mmio, C2VCOUNT ) & 0x00000FFF) != vdisplay)
- ;
+static void crtc2_set_buffer( MatroxDriverData *mdrv,
+ MatroxCrtc2LayerData *mcrtc2,
+ DisplayLayer *layer )
+{
+ volatile __u8 *mmio = mdrv->mmio_base;
mga_out32( mmio, mcrtc2->regs.c2STARTADD1, C2STARTADD1 );
mga_out32( mmio, mcrtc2->regs.c2STARTADD0, C2STARTADD0 );
@@ -711,11 +744,11 @@
crtc2OnOff( mdrv, mcrtc2, 0 );
crtc2_set_regs( mdrv, mcrtc2 );
+ crtc2_set_buffer( mdrv, mcrtc2, layer );
if (!mav->g450)
crtc2_set_mafc( mdrv, 1 );
crtc2OnOff( mdrv, mcrtc2, 1 );
- crtc2_set_buffer( mdrv, mcrtc2, layer );
maven_set_regs( mav, mdrv, &mcrtc2->config, &mcrtc2->adj );
diff -urN DirectFB/include/directfb.h DirectFB/include/directfb.h
--- DirectFB/include/directfb.h Wed Jan 29 15:50:10 2003
+++ DirectFB/include/directfb.h Thu Feb 13 06:37:34 2003
@@ -379,8 +379,9 @@
supported. */
DLCAPS_SATURATION = 0x00000800, /* Adjustment of saturation is
supported. */
- DLCAPS_LEVELS = 0x00001000 /* Adjustment of the layer's level
+ DLCAPS_LEVELS = 0x00001000, /* Adjustment of the layer's level
(z position) is supported. */
+ DLCAPS_FIELD_PARITY = 0x00002000 /* Field parity can be selected */
} DFBDisplayLayerCapabilities;
/*
@@ -397,8 +398,9 @@
interlaced (video) source. */
DLOP_SRC_COLORKEY = 0x00000008, /* Enable source color key. */
DLOP_DST_COLORKEY = 0x00000010, /* Enable dest. color key. */
- DLOP_OPACITY = 0x00000020 /* Make usage of the global alpha
+ DLOP_OPACITY = 0x00000020, /* Make usage of the global alpha
factor set by SetOpacity. */
+ DLOP_FIELD_PARITY = 0x00000040 /* Set field parity */
} DFBDisplayLayerOptions;
/*
@@ -1561,6 +1563,15 @@
DFBResult (*GetCurrentOutputField) (
IDirectFBDisplayLayer *thiz,
int *field
+ );
+
+ /*
+ * For an interlaced display, this sets the field parity.
+ * field: 0 for top field first, and 1 for bottom field first.
+ */
+ DFBResult (*SetFieldParity) (
+ IDirectFBDisplayLayer *thiz,
+ int field
);
/*
diff -urN DirectFB/src/core/layers.c DirectFB/src/core/layers.c
--- DirectFB/src/core/layers.c Thu Feb 13 02:54:08 2003
+++ DirectFB/src/core/layers.c Thu Feb 13 06:37:34 2003
@@ -1122,6 +1122,22 @@
}
DFBResult
+dfb_layer_set_field_parity( DisplayLayer *layer, int field )
+{
+ DFBResult ret;
+
+ if (!layer->funcs->SetFieldParity)
+ return DFB_UNSUPPORTED;
+
+ ret = layer->funcs->SetFieldParity( layer, layer->driver_data,
+ layer->layer_data, field );
+ if (ret)
+ return ret;
+
+ return DFB_OK;
+}
+
+DFBResult
dfb_layer_wait_vsync( DisplayLayer *layer )
{
if (!layer->funcs->WaitVSync)
diff -urN /home/villes/cvs/directfb/DirectFB/src/core/layers.h
DirectFB/src/core/layers.h
--- /home/villes/cvs/directfb/DirectFB/src/core/layers.h Thu Feb 13 02:54:08
2003
+++ DirectFB/src/core/layers.h Thu Feb 13 06:37:34 2003
@@ -84,6 +84,11 @@
void *layer_data,
int *field );
+ DFBResult (*SetFieldParity) ( DisplayLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ int field );
+
DFBResult (*WaitVSync) ( DisplayLayer *layer,
void *driver_data,
void *layer_data );
@@ -304,6 +309,9 @@
DFBResult dfb_layer_set_opacity (DisplayLayer *layer, __u8 opacity);
DFBResult dfb_layer_get_current_output_field( DisplayLayer *layer, int *field );
+
+DFBResult dfb_layer_set_field_parity( DisplayLayer *layer, int field );
+
DFBResult dfb_layer_wait_vsync( DisplayLayer *layer );
DFBResult dfb_layer_set_coloradjustment (DisplayLayer *layer,
diff -urN /home/villes/cvs/directfb/DirectFB/src/display/idirectfbdisplaylayer.c
DirectFB/src/display/idirectfbdisplaylayer.c
--- /home/villes/cvs/directfb/DirectFB/src/display/idirectfbdisplaylayer.c Thu
Dec 19 22:53:38 2002
+++ DirectFB/src/display/idirectfbdisplaylayer.c Thu Feb 13 06:37:34 2003
@@ -209,6 +209,14 @@
}
static DFBResult
+IDirectFBDisplayLayer_SetFieldParity( IDirectFBDisplayLayer *thiz, int field )
+{
+ INTERFACE_GET_DATA(IDirectFBDisplayLayer)
+
+ return dfb_layer_set_field_parity( data->layer, field );
+}
+
+static DFBResult
IDirectFBDisplayLayer_WaitForSync( IDirectFBDisplayLayer *thiz )
{
INTERFACE_GET_DATA(IDirectFBDisplayLayer)
@@ -613,6 +621,7 @@
thiz->SetCursorShape = IDirectFBDisplayLayer_SetCursorShape;
thiz->SetCursorOpacity = IDirectFBDisplayLayer_SetCursorOpacity;
thiz->WaitForSync = IDirectFBDisplayLayer_WaitForSync;
+ thiz->SetFieldParity = IDirectFBDisplayLayer_SetFieldParity;
return DFB_OK;
}
--- mplayer/libvo/vo_dfbmga.c Tue Jan 21 20:55:32 2003
+++ mplayer/libvo/vo_dfbmga.c Thu Feb 13 09:57:17 2003
@@ -91,6 +91,7 @@
static int use_crtc2;
static int use_spic;
static int use_input;
+static int field_parity;
static int osd_changed;
static int osd_dirty;
@@ -223,6 +224,7 @@
use_crtc2 = 1;
use_spic = 1;
use_input = 1;
+ field_parity = -1;
if (vo_subdevice) {
int opt_no = 0;
@@ -243,6 +245,14 @@
use_spic = !opt_no;
vo_subdevice += 5;
opt_no = 0;
+ } else if (!strncmp(vo_subdevice, "fieldparity=", 12)) {
+ vo_subdevice += 12;
+ if (*vo_subdevice == '0' ||
+ *vo_subdevice == '1') {
+ field_parity = *vo_subdevice - '0';
+ vo_subdevice++;
+ }
+ opt_no = 0;
} else if (!strncmp(vo_subdevice, "no", 2)) {
vo_subdevice += 2;
opt_no = 1;
@@ -410,6 +420,11 @@
dlc.flags = DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE;
dlc.buffermode = DLBM_BACKVIDEO;
+ if (field_parity != -1) {
+ dlc.flags |= DLCONF_OPTIONS;
+ dlc.options = DLOP_FIELD_PARITY;
+ }
+
switch (dlc.pixelformat) {
case DSPF_I420:
case DSPF_YV12:
@@ -433,6 +448,10 @@
return -1;
}
crtc2->SetConfiguration( crtc2, &dlc );
+
+ if (field_parity != -1)
+ crtc2->SetFieldParity( crtc2, field_parity );
+
crtc2->GetSurface( crtc2, &c2frame );
c2frame->GetSize( c2frame, &screen_width, &screen_height );