]> git.sesse.net Git - vlc/blobdiff - modules/video_output/msw/direct3d.c
Merge commit 'origin/1.0-bugfix'
[vlc] / modules / video_output / msw / direct3d.c
index cf1bccde0db56344588cbb6e225ff342248be3d2..4503e27165146c8c799d6fbdc9aa5291d39dbf39 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * direct3d.c: Windows Direct3D video output module
  *****************************************************************************
- * Copyright (C) 2006 the VideoLAN team
+ * Copyright (C) 2006-2009 the VideoLAN team
  *$Id$
  *
  * Authors: Damien Fouilleul <damienf@videolan.org>
@@ -39,7 +39,7 @@
 # include "config.h"
 #endif
 
-#include <vlc/vlc.h>
+#include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_interface.h>
 #include <vlc_playlist.h>
@@ -84,9 +84,7 @@ static void Direct3DVoutRenderScene     ( vout_thread_t *, picture_t * );
  * Module descriptor
  *****************************************************************************/
 
-static bool _got_vista_or_above;
-
-static int get_capability_for_osversion(void)
+static bool IsVistaOrAbove(void)
 {
     OSVERSIONINFO winVer;
     winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
@@ -96,27 +94,40 @@ static int get_capability_for_osversion(void)
         if( winVer.dwMajorVersion > 5 )
         {
             /* Windows Vista or above, make this module the default */
-        _got_vista_or_above = true;
-            return 150;
+            return true;
         }
     }
     /* Windows XP or lower, make sure this module isn't the default */
-    _got_vista_or_above = false;
-    return 50;
+    return false;
+}
+
+static int OpenVideoXP( vlc_object_t *obj )
+{
+    return IsVistaOrAbove() ? VLC_EGENERIC : OpenVideo( obj );
 }
 
-vlc_module_begin();
-    set_shortname( "Direct3D" );
-    set_category( CAT_VIDEO );
-    set_subcategory( SUBCAT_VIDEO_VOUT );
-    set_description( _("DirectX 3D video output") );
-    set_capability( "video output", get_capability_for_osversion() );
-    add_shortcut( "direct3d" );
-    set_callbacks( OpenVideo, CloseVideo );
+static int OpenVideoVista( vlc_object_t *obj )
+{
+    return IsVistaOrAbove() ? OpenVideo( obj ) : VLC_EGENERIC;
+}
+
+vlc_module_begin ()
+    set_shortname( "Direct3D" )
+    set_category( CAT_VIDEO )
+    set_subcategory( SUBCAT_VIDEO_VOUT )
+    set_description( N_("DirectX 3D video output") )
+    set_capability( "video output", 50 )
+    add_shortcut( "direct3d" )
+    set_callbacks( OpenVideoXP, CloseVideo )
 
     /* FIXME: Hack to avoid unregistering our window class */
-    linked_with_a_crap_library_which_uses_atexit( );
-vlc_module_end();
+    linked_with_a_crap_library_which_uses_atexit ()
+
+    add_submodule()
+        set_capability( "video output", 150 )
+        add_shortcut( "direct3d" )
+        set_callbacks( OpenVideoVista, CloseVideo )
+vlc_module_end ()
 
 #if 0 /* FIXME */
     /* check if we registered a window class because we need to
@@ -148,21 +159,18 @@ typedef struct
 static int OpenVideo( vlc_object_t *p_this )
 {
     vout_thread_t * p_vout = (vout_thread_t *)p_this;
-    vlc_value_t val;
 
     /* Allocate structure */
-    p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
+    p_vout->p_sys = calloc( 1, sizeof( vout_sys_t ) );
     if( p_vout->p_sys == NULL )
-    {
-        msg_Err( p_vout, "out of memory" );
         return VLC_ENOMEM;
-    }
-    memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
 
     if( VLC_SUCCESS != Direct3DVoutCreate( p_vout ) )
     {
         msg_Err( p_vout, "Direct3D could not be initialized !");
-        goto error;
+        Direct3DVoutRelease( p_vout );
+        free( p_vout->p_sys );
+        return VLC_EGENERIC;
     }
 
     /* Initialisations */
@@ -205,14 +213,18 @@ static int OpenVideo( vlc_object_t *p_this )
     p_vout->p_sys->p_event =
         vlc_object_create( p_vout, sizeof(event_thread_t) );
     p_vout->p_sys->p_event->p_vout = p_vout;
+    p_vout->p_sys->p_event->window_ready = CreateEvent( NULL, TRUE, FALSE, NULL );
     if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread",
-                           E_(EventThread), 0, 1 ) )
+                           EventThread, 0 ) )
     {
         msg_Err( p_vout, "cannot create Vout EventThread" );
+        CloseHandle( p_vout->p_sys->p_event->window_ready );
         vlc_object_release( p_vout->p_sys->p_event );
         p_vout->p_sys->p_event = NULL;
         goto error;
     }
+    WaitForSingleObject( p_vout->p_sys->p_event->window_ready, INFINITE );
+    CloseHandle( p_vout->p_sys->p_event->window_ready );
 
     if( p_vout->p_sys->p_event->b_error )
     {
@@ -226,15 +238,13 @@ static int OpenVideo( vlc_object_t *p_this )
 
     /* Variable to indicate if the window should be on top of others */
     /* Trigger a callback right now */
-    var_Get( p_vout, "video-on-top", &val );
-    var_Set( p_vout, "video-on-top", val );
+    var_TriggerCallback( p_vout, "video-on-top" );
 
     /* disable screensaver by temporarily changing system settings */
     p_vout->p_sys->i_spi_lowpowertimeout = 0;
     p_vout->p_sys->i_spi_powerofftimeout = 0;
     p_vout->p_sys->i_spi_screensavetimeout = 0;
-    var_Get( p_vout, "disable-screensaver", &val);
-    if( val.b_bool ) {
+    if( var_GetBool( p_vout, "disable-screensaver" ) ) {
         msg_Dbg(p_vout, "disabling screen saver");
         SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
             0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
@@ -254,7 +264,7 @@ static int OpenVideo( vlc_object_t *p_this )
     }
     return VLC_SUCCESS;
 
- error:
+error:
     CloseVideo( VLC_OBJECT(p_vout) );
     return VLC_EGENERIC;
 }
@@ -270,6 +280,14 @@ static void CloseVideo( vlc_object_t *p_this )
 
     Direct3DVoutRelease( p_vout );
 
+    if( p_vout->b_fullscreen )
+    {
+        msg_Dbg( p_vout, "Quitting fullscreen" );
+        Win32ToggleFullscreen( p_vout );
+        /* Force fullscreen in the core for the next video */
+        var_SetBool( p_vout, "fullscreen", true );
+    }
+
     if( p_vout->p_sys->p_event )
     {
         vlc_object_detach( p_vout->p_sys->p_event );
@@ -304,11 +322,8 @@ static void CloseVideo( vlc_object_t *p_this )
             p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
     }
 
-    if( p_vout->p_sys )
-    {
-        free( p_vout->p_sys );
-        p_vout->p_sys = NULL;
-    }
+    free( p_vout->p_sys );
+    p_vout->p_sys = NULL;
 }
 
 /*****************************************************************************
@@ -317,10 +332,8 @@ static void CloseVideo( vlc_object_t *p_this )
 static int Init( vout_thread_t *p_vout )
 {
     int i_ret;
-    vlc_value_t val;
 
-    var_Get( p_vout, "directx-hw-yuv", &val );
-    p_vout->p_sys->b_hw_yuv = val.b_bool;
+    p_vout->p_sys->b_hw_yuv = var_GetBool( p_vout, "directx-hw-yuv" );
 
     /* Initialise Direct3D */
     if( VLC_SUCCESS != Direct3DVoutOpen( p_vout ) )
@@ -336,7 +349,7 @@ static int Init( vout_thread_t *p_vout )
     p_vout->output.i_height = p_vout->render.i_height;
     p_vout->output.i_aspect = p_vout->render.i_aspect;
     p_vout->fmt_out = p_vout->fmt_in;
-    E_(UpdateRects)( p_vout, true );
+    UpdateRects( p_vout, true );
 
     /*  create picture pool */
     p_vout->output.i_chroma = 0;
@@ -439,6 +452,28 @@ static int Manage( vout_thread_t *p_vout )
         p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
     }
 
+    /* autoscale toggle */
+    if( p_vout->i_changes & VOUT_SCALE_CHANGE )
+    {
+        p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
+
+        p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
+        p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
+
+        UpdateRects( p_vout, true );
+    }
+
+    /* scaling factor */
+    if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
+    {
+        p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
+
+        p_vout->b_autoscale = false;
+        p_vout->i_zoom =
+            (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
+        UpdateRects( p_vout, true );
+    }
+
     /* Check for cropping / aspect changes */
     if( p_vout->i_changes & VOUT_CROP_CHANGE ||
         p_vout->i_changes & VOUT_ASPECT_CHANGE )
@@ -454,7 +489,7 @@ static int Manage( vout_thread_t *p_vout )
         p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
         p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
         p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
-        E_(UpdateRects)( p_vout, true );
+        UpdateRects( p_vout, true );
     }
 
     /* We used to call the Win32 PeekMessage function here to read the window
@@ -531,7 +566,7 @@ static int Manage( vout_thread_t *p_vout )
     }
 
     /* Check if the event thread is still running */
-    if( p_vout->p_sys->p_event->b_die )
+    if( !vlc_object_alive (p_vout->p_sys->p_event) )
     {
         return VLC_EGENERIC; /* exit */
     }
@@ -736,7 +771,7 @@ static void Direct3DVoutClose( vout_thread_t *p_vout )
        IDirect3DDevice9_Release(p_vout->p_sys->p_d3ddev);
        p_vout->p_sys->p_d3ddev = NULL;
     }
+
     p_vout->p_sys->hmonitor = NULL;
 }
 
@@ -848,17 +883,15 @@ static D3DFORMAT Direct3DVoutFindFormat(vout_thread_t *p_vout, int i_chroma, D3D
     /* it sounds like vista does not support YUV surfaces at all */
         switch( i_chroma )
         {
-            case VLC_FOURCC('U','Y','V','Y'):
-            case VLC_FOURCC('U','Y','N','V'):
-            case VLC_FOURCC('Y','4','2','2'):
+            case VLC_CODEC_UYVY:
             {
                 static const D3DFORMAT formats[] =
                     { D3DFMT_UYVY, D3DFMT_YUY2, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
                 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
             }
-            case VLC_FOURCC('I','4','2','0'):
-            case VLC_FOURCC('I','4','2','2'):
-            case VLC_FOURCC('Y','V','1','2'):
+            case VLC_CODEC_I420:
+            case VLC_CODEC_I422:
+            case VLC_CODEC_YV12:
             {
                 /* typically 3D textures don't support planar format
                 ** fallback to packed version and use CPU for the conversion
@@ -867,8 +900,7 @@ static D3DFORMAT Direct3DVoutFindFormat(vout_thread_t *p_vout, int i_chroma, D3D
                     { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
                 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
             }
-            case VLC_FOURCC('Y','U','Y','2'):
-            case VLC_FOURCC('Y','U','N','V'):
+            case VLC_CODEC_YUYV:
             {
                 static const D3DFORMAT formats[] =
                     { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
@@ -879,25 +911,25 @@ static D3DFORMAT Direct3DVoutFindFormat(vout_thread_t *p_vout, int i_chroma, D3D
 
     switch( i_chroma )
     {
-        case VLC_FOURCC('R', 'V', '1', '5'):
+        case VLC_CODEC_RGB15:
         {
             static const D3DFORMAT formats[] =
                 { D3DFMT_X1R5G5B5 };
             return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
         }
-        case VLC_FOURCC('R', 'V', '1', '6'):
+        case VLC_CODEC_RGB16:
         {
             static const D3DFORMAT formats[] =
                 { D3DFMT_R5G6B5 };
             return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
         }
-        case VLC_FOURCC('R', 'V', '2', '4'):
+        case VLC_CODEC_RGB24:
         {
             static const D3DFORMAT formats[] =
                 { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
             return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
         }
-        case VLC_FOURCC('R', 'V', '3', '2'):
+        case VLC_CODEC_RGB32:
         {
             static const D3DFORMAT formats[] =
                 { D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8 };
@@ -945,32 +977,32 @@ static int Direct3DVoutSetOutputFormat(vout_thread_t *p_vout, D3DFORMAT format)
     switch( format )
     {
         case D3DFMT_YUY2:
-            p_vout->output.i_chroma = VLC_FOURCC('Y', 'U', 'Y', '2');
+            p_vout->output.i_chroma = VLC_CODEC_YUYV;
             break;
         case D3DFMT_UYVY:
-            p_vout->output.i_chroma = VLC_FOURCC('U', 'Y', 'V', 'Y');
+            p_vout->output.i_chroma = VLC_CODEC_UYVY;
             break;
         case D3DFMT_R8G8B8:
-            p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '2', '4');
+            p_vout->output.i_chroma = VLC_CODEC_RGB24;
             p_vout->output.i_rmask = 0xff0000;
             p_vout->output.i_gmask = 0x00ff00;
             p_vout->output.i_bmask = 0x0000ff;
             break;
         case D3DFMT_X8R8G8B8:
         case D3DFMT_A8R8G8B8:
-            p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '3', '2');
+            p_vout->output.i_chroma = VLC_CODEC_RGB32;
             p_vout->output.i_rmask = 0x00ff0000;
             p_vout->output.i_gmask = 0x0000ff00;
             p_vout->output.i_bmask = 0x000000ff;
             break;
         case D3DFMT_R5G6B5:
-            p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '6');
+            p_vout->output.i_chroma = VLC_CODEC_RGB16;
             p_vout->output.i_rmask = (0x1fL)<<11;
             p_vout->output.i_gmask = (0x3fL)<<5;
             p_vout->output.i_bmask = (0x1fL)<<0;
             break;
         case D3DFMT_X1R5G5B5:
-            p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '5');
+            p_vout->output.i_chroma = VLC_CODEC_RGB15;
             p_vout->output.i_rmask = (0x1fL)<<10;
             p_vout->output.i_gmask = (0x1fL)<<5;
             p_vout->output.i_bmask = (0x1fL)<<0;
@@ -1034,7 +1066,7 @@ static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics
 
         /* fill surface with black color */
         IDirect3DDevice9_ColorFill(p_d3ddev, p_d3dsurf, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
+
         /* assign surface to internal structure */
         p_pic->p_sys = (void *)p_d3dsurf;
 
@@ -1042,7 +1074,7 @@ static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics
          * picture_t structures */
         switch( p_vout->output.i_chroma )
         {
-            case VLC_FOURCC('R','G','B','2'):
+            case VLC_CODEC_RGB8:
                 p_pic->p->i_lines = p_vout->output.i_height;
                 p_pic->p->i_visible_lines = p_vout->output.i_height;
                 p_pic->p->i_pixel_pitch = 1;
@@ -1050,8 +1082,8 @@ static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics
                     p_pic->p->i_pixel_pitch;
                 p_pic->i_planes = 1;
             break;
-            case VLC_FOURCC('R','V','1','5'):
-            case VLC_FOURCC('R','V','1','6'):
+            case VLC_CODEC_RGB15:
+            case VLC_CODEC_RGB16:
                 p_pic->p->i_lines = p_vout->output.i_height;
                 p_pic->p->i_visible_lines = p_vout->output.i_height;
                 p_pic->p->i_pixel_pitch = 2;
@@ -1059,7 +1091,7 @@ static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics
                     p_pic->p->i_pixel_pitch;
                 p_pic->i_planes = 1;
             break;
-            case VLC_FOURCC('R','V','2','4'):
+            case VLC_CODEC_RGB24:
                 p_pic->p->i_lines = p_vout->output.i_height;
                 p_pic->p->i_visible_lines = p_vout->output.i_height;
                 p_pic->p->i_pixel_pitch = 3;
@@ -1067,7 +1099,7 @@ static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics
                     p_pic->p->i_pixel_pitch;
                 p_pic->i_planes = 1;
             break;
-            case VLC_FOURCC('R','V','3','2'):
+            case VLC_CODEC_RGB32:
                 p_pic->p->i_lines = p_vout->output.i_height;
                 p_pic->p->i_visible_lines = p_vout->output.i_height;
                 p_pic->p->i_pixel_pitch = 4;
@@ -1075,8 +1107,8 @@ static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics
                     p_pic->p->i_pixel_pitch;
                 p_pic->i_planes = 1;
                 break;
-            case VLC_FOURCC('U','Y','V','Y'):
-            case VLC_FOURCC('Y','U','Y','2'):
+            case VLC_CODEC_UYVY:
+            case VLC_CODEC_YUYV:
                 p_pic->p->i_lines = p_vout->output.i_height;
                 p_pic->p->i_visible_lines = p_vout->output.i_height;
                 p_pic->p->i_pixel_pitch = 2;
@@ -1380,41 +1412,43 @@ static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic )
     }
 
     /* Setup vertices */
-    f_width  = (float)(p_vout->output.i_width) + 1;
-    f_height = (float)(p_vout->output.i_height) + 1;
+    f_width  = (float)(p_vout->output.i_width);
+    f_height = (float)(p_vout->output.i_height);
 
-    p_vertices[0].x       = 0.0f;       // left
-    p_vertices[0].y       = 0.0f;       // top
+    /* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */
+    /* http://www.sjbrown.co.uk/2003/05/01/fix-directx-rasterisation/ */
+    p_vertices[0].x       = -0.5f;       // left
+    p_vertices[0].y       = -0.5f;       // top
     p_vertices[0].z       = 0.0f;
     p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
     p_vertices[0].rhw     = 1.0f;
     p_vertices[0].tu      = 0.0f;
     p_vertices[0].tv      = 0.0f;
-    p_vertices[1].x       = f_width;    // right
-    p_vertices[1].y       = 0.0f;       // top
+
+    p_vertices[1].x       = f_width - 0.5f;    // right
+    p_vertices[1].y       = -0.5f;       // top
     p_vertices[1].z       = 0.0f;
     p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
     p_vertices[1].rhw     = 1.0f;
     p_vertices[1].tu      = 1.0f;
     p_vertices[1].tv      = 0.0f;
-    p_vertices[2].x       = f_width;    // right
-    p_vertices[2].y       = f_height;   // bottom
+
+    p_vertices[2].x       = f_width - 0.5f;    // right
+    p_vertices[2].y       = f_height - 0.5f;   // bottom
     p_vertices[2].z       = 0.0f;
     p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
     p_vertices[2].rhw     = 1.0f;
     p_vertices[2].tu      = 1.0f;
     p_vertices[2].tv      = 1.0f;
-    p_vertices[3].x       = 0.0f;       // left
-    p_vertices[3].y       = f_height;   // bottom
+
+    p_vertices[3].x       = -0.5f;       // left
+    p_vertices[3].y       = f_height - 0.5f;   // bottom
     p_vertices[3].z       = 0.0f;
     p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
     p_vertices[3].rhw     = 1.0f;
     p_vertices[3].tu      = 0.0f;
     p_vertices[3].tv      = 1.0f;
+
     hr= IDirect3DVertexBuffer9_Unlock(p_d3dvtc);
     if( FAILED(hr) )
     {
@@ -1450,16 +1484,8 @@ static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic )
         IDirect3DDevice9_EndScene(p_d3ddev);
         return;
     }
-    // we use FVF instead of vertex shader
-    hr = IDirect3DDevice9_SetVertexShader(p_d3ddev, NULL);
-    if( FAILED(hr) )
-    {
-        msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
-        IDirect3DDevice9_EndScene(p_d3ddev);
-        return;
-    }
 
+    // we use FVF instead of vertex shader
     hr = IDirect3DDevice9_SetFVF(p_d3ddev, D3DFVF_CUSTOMVERTEX);
     if( FAILED(hr) )
     {