]> git.sesse.net Git - vlc/commitdiff
* Added double-buffering for the directx plugin in overlay mode.
authorGildas Bazin <gbazin@videolan.org>
Sun, 27 Jan 2002 22:14:52 +0000 (22:14 +0000)
committerGildas Bazin <gbazin@videolan.org>
Sun, 27 Jan 2002 22:14:52 +0000 (22:14 +0000)
* Several directx bug-fixes:
    - implemented the right behaviour on exit.
    - fixed bug preventing the creation of several windows.
        (the wall filter is working now :-))
    - fixed unnecessary background redraws (it made the video flicker).
    - fixed bug where we were losing the video display because of lost
        surfaces in video memory.
    - when using hardware overlay, the output window will now specify:
        "(using hardware overlay)".

plugins/directx/vout_directx.c
plugins/directx/vout_directx.h
plugins/directx/vout_events.c

index fbda1e8bee83e1bb24e0a5b8f4e6d7bce67c2034..1ca5d9c44b12320f32f40a0a8406048430712244 100644 (file)
@@ -2,7 +2,7 @@
  * vout_directx.c: Windows DirectX video output display method
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: vout_directx.c,v 1.19 2002/01/17 23:02:45 gbazin Exp $
+ * $Id: vout_directx.c,v 1.20 2002/01/27 22:14:52 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -285,6 +285,11 @@ static int vout_Init( vout_thread_t *p_vout )
 
     NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
 
+    /* Change the window title bar text */
+    if( p_vout->p_sys->b_using_overlay )
+        SetWindowText( p_vout->p_sys->hwnd,
+                       "VLC DirectX (using hardware overlay)" );
+
     return( 0 );
 }
 
@@ -315,7 +320,8 @@ static void vout_Destroy( vout_thread_t *p_vout )
     p_vout->p_sys->b_event_thread_die = 1;
     /* we need to be sure DirectXEventThread won't stay stuck in GetMessage,
      * so we send a fake message */
-    if( p_vout->p_sys->i_event_thread_status == THREAD_READY )
+    if( p_vout->p_sys->i_event_thread_status == THREAD_READY &&
+        p_vout->p_sys->hwnd )
     {
         PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'q', 0);
         vlc_thread_join( p_vout->p_sys->event_thread_id );
@@ -353,7 +359,7 @@ static int vout_Manage( vout_thread_t *p_vout )
         if( !p_vout->p_sys->b_using_overlay )
             InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
         else
-          DirectXUpdateOverlay( p_vout );
+            DirectXUpdateOverlay( p_vout );
         p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
         p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE;
     }
@@ -368,7 +374,7 @@ static int vout_Manage( vout_thread_t *p_vout )
         if( !p_vout->p_sys->b_using_overlay )
             InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
         else
-          DirectXUpdateOverlay( p_vout );
+            DirectXUpdateOverlay( p_vout );
         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
         p_vout->p_sys->i_changes &= ~VOUT_SIZE_CHANGE;
     }
@@ -457,8 +463,6 @@ static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
 {
     HRESULT dxresult;
 
-    intf_WarnMsg( 8, "vout: vout_Display" );
-
     if( (p_vout->p_sys->p_display == NULL) )
     {
         intf_WarnMsg( 3, "vout error: vout_Display no display!!" );
@@ -476,10 +480,24 @@ static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
 
         /* Blit video surface to display */
         dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
-                                           &p_vout->p_sys->rect_dest,
+                                           &p_vout->p_sys->rect_dest_clipped,
+                                           p_pic->p_sys->p_surface,
+                                           &p_vout->p_sys->rect_src_clipped,
+                                           0, &ddbltfx );
+        if ( dxresult == DDERR_SURFACELOST )
+        {
+            /* Our surface can be lost so be sure
+             * to check this and restore it if needed */
+            IDirectDrawSurface3_Restore( p_vout->p_sys->p_display );
+
+            /* Now that the surface has been restored try to display again */
+            dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
+                                           &p_vout->p_sys->rect_dest_clipped,
                                            p_pic->p_sys->p_surface,
-                                           NULL,
+                                           &p_vout->p_sys->rect_src_clipped,
                                            0, &ddbltfx );
+        }
+
         if( dxresult != DD_OK )
         {
             intf_WarnMsg( 3, "vout: could not Blit the surface" );
@@ -491,7 +509,23 @@ static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
     {
 
         /* Flip the overlay buffers */
-        //dxresult = IDirectDrawSurface3_Flip(p_pic->p_sys->p_surface, NULL, 0 );
+        dxresult = IDirectDrawSurface3_Flip( p_pic->p_sys->p_front_surface,
+                                             NULL, DDFLIP_WAIT );
+        if ( dxresult == DDERR_SURFACELOST )
+        {
+            /* Our surface can be lost so be sure
+             * to check this and restore it if needed */
+            IDirectDrawSurface3_Restore( p_vout->p_sys->p_display );
+            IDirectDrawSurface3_Restore( p_pic->p_sys->p_front_surface );
+
+            /* Now that the surface has been restored try to display again */
+            dxresult = IDirectDrawSurface3_Flip( p_pic->p_sys->p_front_surface,
+                                                 NULL, DDFLIP_WAIT );
+            DirectXUpdateOverlay( p_vout );
+        }
+
+        if( dxresult != DD_OK )
+            intf_WarnMsg( 8, "vout: couldn't flip overlay surface" );
 
         if( !DirectXGetSurfaceDesc( p_pic ) )
         {
@@ -507,11 +541,10 @@ static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
             return;
         }
 
-        /* set currently displayed pic !!! faux*/
-        p_vout->p_sys->p_current_surface = p_pic->p_sys->p_surface;
+        /* set currently displayed pic */
+        p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
     }
 
-    intf_WarnMsg( 8, "vout: vout_Display End" );
 }
 
 
@@ -758,15 +791,15 @@ static int DirectXCreateSurface( vout_thread_t *p_vout,
         ddsd.dwFlags = DDSD_CAPS |
                        DDSD_HEIGHT |
                        DDSD_WIDTH |
-          //DDSD_BACKBUFFERCOUNT |
+                       DDSD_BACKBUFFERCOUNT |
                        DDSD_PIXELFORMAT;
         ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY |
-          //                  DDSCAPS_COMPLEX |
-          //DDSCAPS_FLIP |
+                              DDSCAPS_COMPLEX |
+                              DDSCAPS_FLIP |
                               DDSCAPS_VIDEOMEMORY;
         ddsd.dwHeight = p_vout->render.i_height;
         ddsd.dwWidth = p_vout->render.i_width;
-        ddsd.dwBackBufferCount = 0;                       /* One back buffer */
+        ddsd.dwBackBufferCount = 1;                       /* One back buffer */
 
         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
                                                &ddsd,
@@ -975,8 +1008,10 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
     p_vout->output.i_chroma = p_vout->render.i_chroma;
 
     /* hack */
+#if 1
     if( p_vout->render.i_chroma == FOURCC_I420 )
         p_vout->output.i_chroma = FOURCC_YV12;
+#endif
 
     /* First we try to create an overlay surface.
      * It looks like with most hardware it's not possible to create several
@@ -991,6 +1026,8 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
         if( DirectXCreateSurface( p_vout, &p_surface, p_vout->output.i_chroma,
                                   p_vout->p_sys->b_using_overlay ) )
         {
+            DDSCAPS dds_caps;
+
             /* Allocate internal structure */
             p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
             if( p_pic[0].p_sys == NULL )
@@ -998,8 +1035,25 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
                 DirectXCloseSurface( p_vout, p_surface );
                 return -1;
             }
-            p_pic[0].p_sys->p_surface = p_surface;
-            p_vout->p_sys->p_current_surface = p_surface;
+
+            /* set front buffer */
+            p_pic[0].p_sys->p_front_surface = p_surface;
+
+            /* Get the back buffer */
+            memset( &dds_caps, 0, sizeof( DDSCAPS ));
+            dds_caps.dwCaps = DDSCAPS_BACKBUFFER;
+            if( DD_OK != IDirectDrawSurface3_GetAttachedSurface(
+                                                p_surface, &dds_caps,
+                                                &p_pic[0].p_sys->p_surface ) )
+            {
+                intf_WarnMsg( 3, "vout: NewPictureVec couldn't get "
+                              "back buffer" );
+                /* front buffer is the same as back buffer */
+                p_pic[0].p_sys->p_surface = p_surface;
+            }
+
+
+            p_vout->p_sys->p_current_surface= p_pic[0].p_sys->p_front_surface;
             DirectXUpdateOverlay( p_vout );
             I_OUTPUTPICTURES = 1;
         }
@@ -1030,6 +1084,7 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
                     return -1;
                 }
                 p_pic[i].p_sys->p_surface = p_surface;
+                p_pic[i].p_sys->p_front_surface = NULL;
                 I_OUTPUTPICTURES++;
 
             }
@@ -1083,6 +1138,12 @@ static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
 
     for( i = 0; i < i_num_pics; i++ )
     {
+#if 0
+        if( p_pic->p_sys->p_front_surface && 
+            ( p_pic->p_sys->p_surface != p_pic->p_sys->p_front_surface ) )
+            DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
+#endif
+
         DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_surface );
 
         for( i = 0; i < i_num_pics; i++ )
@@ -1158,7 +1219,7 @@ static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic,
 
             p_pic->i_planes = 1;
             break;
-#if 0
+
         case FOURCC_I420:
 
             p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
@@ -1184,6 +1245,7 @@ static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic,
             p_pic->i_planes = 3;
             break;
 
+#if 0
         case FOURCC_Y211:
 
             p_pic->p->p_pixels = p_pic->p_sys->p_image->data
index 4082b1916c32e176a30e2c68818a700d9b7c51aa..eaec48533c57896560f8a9138a1e782b8a20e5c3 100644 (file)
@@ -2,7 +2,7 @@
  * vout_directx.h: Windows DirectX video output header file
  *****************************************************************************
  * Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: vout_directx.h,v 1.2 2002/01/17 23:02:45 gbazin Exp $
+ * $Id: vout_directx.h,v 1.3 2002/01/27 22:14:52 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -88,6 +88,7 @@ typedef struct picture_sys_s
 {
     LPDIRECTDRAWSURFACE3 p_surface;
     DDSURFACEDESC        ddsd;
+    LPDIRECTDRAWSURFACE3 p_front_surface;
 
 } picture_sys_t;
 
index af35919c87671f77843d80aff291a3173a29c61c..fcdfece54ad16d27057bbf3417f3828c175187e9 100644 (file)
@@ -2,7 +2,7 @@
  * vout_events.c: Windows DirectX video output events handler
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: vout_events.c,v 1.9 2002/01/21 07:00:21 gbazin Exp $
+ * $Id: vout_events.c,v 1.10 2002/01/27 22:14:52 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -102,16 +102,6 @@ void DirectXEventThread( vout_thread_t *p_vout )
         switch( msg.message )
         {
 
-#if 0
-        case WM_PAINT:
-            intf_WarnMsg( 4, "vout: vout_Manage WM_PAINT" );
-            break;
-
-        case WM_ERASEBKGND:
-            intf_WarnMsg( 4, "vout: vout_Manage WM_ERASEBKGND" );
-            break;
-#endif
-
         case WM_MOUSEMOVE:
             if( p_vout->p_sys->b_cursor )
             {
@@ -126,6 +116,7 @@ void DirectXEventThread( vout_thread_t *p_vout )
                     p_vout->p_sys->i_lastmoved = mdate();
                 }
             }
+            DispatchMessage(&msg);
             break;
 
         case WM_RBUTTONUP:
@@ -221,11 +212,9 @@ void DirectXEventThread( vout_thread_t *p_vout )
 
     if( msg.message == WM_QUIT )
     {
-        intf_WarnMsg( 3, "vout: DirectXEventThread WM_QUIT" );
+        intf_WarnMsg( 3, "vout: DirectXEventThread WM_QUIT... "
+                      "shouldn't happen!!" );
         p_vout->p_sys->hwnd = NULL; /* Window already destroyed */
-
-        /* exit application */
-        p_main->p_intf->b_die = 1;
     }
 
     intf_WarnMsg( 3, "vout: DirectXEventThread Terminating" );
@@ -322,8 +311,13 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
     /* register the window class */
     if (!RegisterClassEx(&wc))
     {
-        intf_WarnMsg( 3, "vout: DirectXCreateWindow register window FAILED" );
-        return (1);
+        /* Check why it failed. If it's because one already exists then fine */
+        WNDCLASS wndclass;
+        if( !GetClassInfo( hInstance, "VLC DirectX", &wndclass ) )
+        {
+            intf_ErrMsg( "vout: DirectXCreateWindow RegisterClass FAILED" );
+            return (1);
+        }
     }
 
     /* when you create a window you give the dimensions you wish it to have.
@@ -341,8 +335,8 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
                     "VLC DirectX",                  /* window title bar text */
                     WS_OVERLAPPEDWINDOW
                     | WS_SIZEBOX,               /* window style */
-                    10,                              /* default X coordinate */
-                    10,                              /* default Y coordinate */
+                    CW_USEDEFAULT,                   /* default X coordinate */
+                    0,                               /* default Y coordinate */
                     rect_window.right - rect_window.left,    /* window width */
                     rect_window.bottom - rect_window.top,   /* window height */
                     NULL,                                /* no parent window */
@@ -373,8 +367,6 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
  *****************************************************************************/
 static void DirectXCloseWindow( vout_thread_t *p_vout )
 {
-    HINSTANCE hInstance;
-
     intf_WarnMsg( 3, "vout: DirectXCloseWindow" );
     if( p_vout->p_sys->hwnd != NULL )
     {
@@ -382,9 +374,9 @@ static void DirectXCloseWindow( vout_thread_t *p_vout )
         p_vout->p_sys->hwnd = NULL;
     }
 
-    hInstance = GetModuleHandle(NULL);
-    UnregisterClass( "VLC DirectX",                            /* class name */
-                     hInstance );          /* handle to application instance */
+    /* We don't unregister the Window Class because it could lead to race
+     * conditions and it will be done anyway by the system when the app will
+     * exit */
 
     /* free window background brush */
     if( p_vout->p_sys->hbrush != NULL )
@@ -514,7 +506,8 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
                       p_vout->p_sys->i_window_height );
 
         DirectXUpdateRects( p_vout );
-        if( p_vout->p_sys->b_using_overlay )
+        if( p_vout->p_sys->b_using_overlay &&
+            !p_vout->p_sys->b_event_thread_die )
             DirectXUpdateOverlay( p_vout );
 
         /* signal the size change */
@@ -535,13 +528,15 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
     /* the user wants to close the window */
     case WM_CLOSE:
         intf_WarnMsg( 4, "vout: WinProc WM_CLOSE" );
+        /* exit application */
+        p_main->p_intf->b_die = 1;
+        return 0;
         break;
 
     /* the window has been closed so shut down everything now */
     case WM_DESTROY:
         intf_WarnMsg( 4, "vout: WinProc WM_DESTROY" );
-        /* exit application */
-        p_main->p_intf->b_die = 1;
+        /* just destroy the window */
         PostQuitMessage( 0 );
         return 0;
         break;
@@ -556,6 +551,34 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
         }
         break;
 
+#if 0
+    case WM_PAINT:
+        intf_WarnMsg( 4, "vout: WinProc WM_PAINT" );
+        break;
+#endif
+
+    case WM_ERASEBKGND:
+        p_vout = (vout_thread_t *)GetWindowLong( hwnd, GWL_USERDATA );
+        if( !p_vout->p_sys->b_using_overlay )
+        {
+            /* We want to eliminate unnecessary background redraws which create
+             * an annoying flickering */
+            int i_width, i_height, i_x, i_y;
+            RECT rect_temp;
+            GetClipBox( (HDC)wParam, &rect_temp );
+#if 0
+            intf_WarnMsg( 4, "vout: WinProc WM_ERASEBKGND %i,%i,%i,%i",
+                          rect_temp.left, rect_temp.top,
+                          rect_temp.right, rect_temp.bottom );
+#endif
+            vout_PlacePicture( p_vout, p_vout->p_sys->i_window_width,
+                               p_vout->p_sys->i_window_height,
+                               &i_x, &i_y, &i_width, &i_height );
+            ExcludeClipRect( (HDC)wParam, i_x, i_y,
+                             i_x + i_width, i_y + i_height );
+        }
+        break;
+
 #if 0
     default:
         intf_WarnMsg( 4, "vout: WinProc WM Default %i", message );