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 );

Reply via email to