direct3d.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:55k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * direct3d.c: Windows Direct3D video output module
  3.  *****************************************************************************
  4.  * Copyright (C) 2006-2009 the VideoLAN team
  5.  *$Id: 8951bbe1cfc0230d0e9f0804434b5ec0434a9897 $
  6.  *
  7.  * Authors: Damien Fouilleul <damienf@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble:
  25.  *
  26.  * This plugin will use YUV surface if supported, using YUV will result in
  27.  * the best video quality (hardware filering when rescaling the picture)
  28.  * and the fastest display as it requires less processing.
  29.  *
  30.  * If YUV overlay is not supported this plugin will use RGB offscreen video
  31.  * surfaces that will be blitted onto the primary surface (display) to
  32.  * effectively display the pictures.
  33.  *
  34.  *****************************************************************************/
  35. #include <errno.h>                                                 /* ENOMEM */
  36. #ifdef HAVE_CONFIG_H
  37. # include "config.h"
  38. #endif
  39. #include <vlc_common.h>
  40. #include <vlc_plugin.h>
  41. #include <vlc_interface.h>
  42. #include <vlc_playlist.h>
  43. #include <vlc_vout.h>
  44. #include <windows.h>
  45. #include <d3d9.h>
  46. #include "vout.h"
  47. /*****************************************************************************
  48.  * Local prototypes.
  49.  *****************************************************************************/
  50. static int  OpenVideo  ( vlc_object_t * );
  51. static void CloseVideo ( vlc_object_t * );
  52. static int  Init      ( vout_thread_t * );
  53. static void End       ( vout_thread_t * );
  54. static int  Manage    ( vout_thread_t * );
  55. static void Display   ( vout_thread_t *, picture_t * );
  56. static void FirstDisplay( vout_thread_t *, picture_t * );
  57. static int Direct3DVoutCreate     ( vout_thread_t * );
  58. static void Direct3DVoutRelease   ( vout_thread_t * );
  59. static int  Direct3DVoutOpen      ( vout_thread_t * );
  60. static void Direct3DVoutClose     ( vout_thread_t * );
  61. static int Direct3DVoutResetDevice( vout_thread_t * );
  62. static int Direct3DVoutCreatePictures   ( vout_thread_t *, size_t );
  63. static void Direct3DVoutReleasePictures ( vout_thread_t * );
  64. static int Direct3DVoutLockSurface  ( vout_thread_t *, picture_t * );
  65. static int Direct3DVoutUnlockSurface( vout_thread_t *, picture_t * );
  66. static int Direct3DVoutCreateScene      ( vout_thread_t * );
  67. static void Direct3DVoutReleaseScene    ( vout_thread_t * );
  68. static void Direct3DVoutRenderScene     ( vout_thread_t *, picture_t * );
  69. /*****************************************************************************
  70.  * Module descriptor
  71.  *****************************************************************************/
  72. static bool IsVistaOrAbove(void)
  73. {
  74.     OSVERSIONINFO winVer;
  75.     winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  76.     if( GetVersionEx(&winVer) )
  77.     {
  78.         if( winVer.dwMajorVersion > 5 )
  79.         {
  80.             /* Windows Vista or above, make this module the default */
  81.             return true;
  82.         }
  83.     }
  84.     /* Windows XP or lower, make sure this module isn't the default */
  85.     return false;
  86. }
  87. static int OpenVideoXP( vlc_object_t *obj )
  88. {
  89.     return IsVistaOrAbove() ? VLC_EGENERIC : OpenVideo( obj );
  90. }
  91. static int OpenVideoVista( vlc_object_t *obj )
  92. {
  93.     return IsVistaOrAbove() ? OpenVideo( obj ) : VLC_EGENERIC;
  94. }
  95. vlc_module_begin ()
  96.     set_shortname( "Direct3D" )
  97.     set_category( CAT_VIDEO )
  98.     set_subcategory( SUBCAT_VIDEO_VOUT )
  99.     set_description( N_("DirectX 3D video output") )
  100.     set_capability( "video output", 50 )
  101.     add_shortcut( "direct3d" )
  102.     set_callbacks( OpenVideoXP, CloseVideo )
  103.     /* FIXME: Hack to avoid unregistering our window class */
  104.     linked_with_a_crap_library_which_uses_atexit ()
  105.     add_submodule()
  106.         set_capability( "video output", 150 )
  107.         add_shortcut( "direct3d" )
  108.         set_callbacks( OpenVideoVista, CloseVideo )
  109. vlc_module_end ()
  110. #if 0 /* FIXME */
  111.     /* check if we registered a window class because we need to
  112.      * unregister it */
  113.     WNDCLASS wndclass;
  114.     if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
  115.         UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
  116. #endif
  117. /*****************************************************************************
  118.  * CUSTOMVERTEX:
  119.  *****************************************************************************
  120.  *****************************************************************************/
  121. typedef struct
  122. {
  123.     FLOAT       x,y,z;      // vertex untransformed position
  124.     FLOAT       rhw;        // eye distance
  125.     D3DCOLOR    diffuse;    // diffuse color
  126.     FLOAT       tu, tv;     // texture relative coordinates
  127. } CUSTOMVERTEX;
  128. #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  129. /*****************************************************************************
  130.  * OpenVideo: allocate Vout video thread output method
  131.  *****************************************************************************
  132.  * This function allocates and initialize the Direct3D vout method.
  133.  *****************************************************************************/
  134. static int OpenVideo( vlc_object_t *p_this )
  135. {
  136.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  137.     /* Allocate structure */
  138.     p_vout->p_sys = calloc( 1, sizeof( vout_sys_t ) );
  139.     if( p_vout->p_sys == NULL )
  140.         return VLC_ENOMEM;
  141.     if( VLC_SUCCESS != Direct3DVoutCreate( p_vout ) )
  142.     {
  143.         msg_Err( p_vout, "Direct3D could not be initialized !");
  144.         Direct3DVoutRelease( p_vout );
  145.         free( p_vout->p_sys );
  146.         return VLC_EGENERIC;
  147.     }
  148.     /* Initialisations */
  149.     p_vout->pf_init = Init;
  150.     p_vout->pf_end = End;
  151.     p_vout->pf_manage = Manage;
  152.     p_vout->pf_render = Direct3DVoutRenderScene;
  153.     p_vout->pf_display = FirstDisplay;
  154.     p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
  155.     p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
  156.     p_vout->p_sys->i_changes = 0;
  157.     vlc_mutex_init( &p_vout->p_sys->lock );
  158.     SetRectEmpty( &p_vout->p_sys->rect_display );
  159.     SetRectEmpty( &p_vout->p_sys->rect_parent );
  160.     var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  161.     var_Create( p_vout, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  162.     p_vout->p_sys->b_cursor_hidden = 0;
  163.     p_vout->p_sys->i_lastmoved = mdate();
  164.     p_vout->p_sys->i_mouse_hide_timeout =
  165.         var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
  166.     var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  167.     var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  168.     /* Set main window's size */
  169.     p_vout->p_sys->i_window_width = p_vout->i_window_width;
  170.     p_vout->p_sys->i_window_height = p_vout->i_window_height;
  171.     /* Create the Vout EventThread, this thread is created by us to isolate
  172.      * the Win32 PeekMessage function calls. We want to do this because
  173.      * Windows can stay blocked inside this call for a long time, and when
  174.      * this happens it thus blocks vlc's video_output thread.
  175.      * Vout EventThread will take care of the creation of the video
  176.      * window (because PeekMessage has to be called from the same thread which
  177.      * created the window). */
  178.     msg_Dbg( p_vout, "creating Vout EventThread" );
  179.     p_vout->p_sys->p_event =
  180.         vlc_object_create( p_vout, sizeof(event_thread_t) );
  181.     p_vout->p_sys->p_event->p_vout = p_vout;
  182.     p_vout->p_sys->p_event->window_ready = CreateEvent( NULL, TRUE, FALSE, NULL );
  183.     if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread",
  184.                            EventThread, 0 ) )
  185.     {
  186.         msg_Err( p_vout, "cannot create Vout EventThread" );
  187.         CloseHandle( p_vout->p_sys->p_event->window_ready );
  188.         vlc_object_release( p_vout->p_sys->p_event );
  189.         p_vout->p_sys->p_event = NULL;
  190.         goto error;
  191.     }
  192.     WaitForSingleObject( p_vout->p_sys->p_event->window_ready, INFINITE );
  193.     CloseHandle( p_vout->p_sys->p_event->window_ready );
  194.     if( p_vout->p_sys->p_event->b_error )
  195.     {
  196.         msg_Err( p_vout, "Vout EventThread failed" );
  197.         goto error;
  198.     }
  199.     vlc_object_attach( p_vout->p_sys->p_event, p_vout );
  200.     msg_Dbg( p_vout, "Vout EventThread running" );
  201.     /* Variable to indicate if the window should be on top of others */
  202.     /* Trigger a callback right now */
  203.     var_TriggerCallback( p_vout, "video-on-top" );
  204.     /* disable screensaver by temporarily changing system settings */
  205.     p_vout->p_sys->i_spi_lowpowertimeout = 0;
  206.     p_vout->p_sys->i_spi_powerofftimeout = 0;
  207.     p_vout->p_sys->i_spi_screensavetimeout = 0;
  208.     if( var_GetBool( p_vout, "disable-screensaver" ) ) {
  209.         msg_Dbg(p_vout, "disabling screen saver");
  210.         SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
  211.             0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
  212.         if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
  213.             SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
  214.         }
  215.         SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
  216.             &(p_vout->p_sys->i_spi_powerofftimeout), 0);
  217.         if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
  218.             SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
  219.         }
  220.         SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
  221.             &(p_vout->p_sys->i_spi_screensavetimeout), 0);
  222.         if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
  223.             SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
  224.         }
  225.     }
  226.     return VLC_SUCCESS;
  227. error:
  228.     CloseVideo( VLC_OBJECT(p_vout) );
  229.     return VLC_EGENERIC;
  230. }
  231. /*****************************************************************************
  232.  * CloseVideo: destroy Sys video thread output method
  233.  *****************************************************************************
  234.  * Terminate an output method created by Create
  235.  *****************************************************************************/
  236. static void CloseVideo( vlc_object_t *p_this )
  237. {
  238.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  239.     Direct3DVoutRelease( p_vout );
  240.     if( p_vout->b_fullscreen )
  241.     {
  242.         msg_Dbg( p_vout, "Quitting fullscreen" );
  243.         Win32ToggleFullscreen( p_vout );
  244.         /* Force fullscreen in the core for the next video */
  245.         var_SetBool( p_vout, "fullscreen", true );
  246.     }
  247.     if( p_vout->p_sys->p_event )
  248.     {
  249.         vlc_object_detach( p_vout->p_sys->p_event );
  250.         /* Kill Vout EventThread */
  251.         vlc_object_kill( p_vout->p_sys->p_event );
  252.         /* we need to be sure Vout EventThread won't stay stuck in
  253.          * GetMessage, so we send a fake message */
  254.         if( p_vout->p_sys->hwnd )
  255.         {
  256.             PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
  257.         }
  258.         vlc_thread_join( p_vout->p_sys->p_event );
  259.         vlc_object_release( p_vout->p_sys->p_event );
  260.     }
  261.     vlc_mutex_destroy( &p_vout->p_sys->lock );
  262.     /* restore screensaver system settings */
  263.     if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
  264.         SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
  265.             p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
  266.     }
  267.     if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
  268.         SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
  269.             p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
  270.     }
  271.     if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
  272.         SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
  273.             p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
  274.     }
  275.     free( p_vout->p_sys );
  276.     p_vout->p_sys = NULL;
  277. }
  278. /*****************************************************************************
  279.  * Init: initialize Direct3D video thread output method
  280.  *****************************************************************************/
  281. static int Init( vout_thread_t *p_vout )
  282. {
  283.     int i_ret;
  284.     p_vout->p_sys->b_hw_yuv = var_GetBool( p_vout, "directx-hw-yuv" );
  285.     /* Initialise Direct3D */
  286.     if( VLC_SUCCESS != Direct3DVoutOpen( p_vout ) )
  287.     {
  288.         msg_Err( p_vout, "cannot initialize Direct3D" );
  289.         return VLC_EGENERIC;
  290.     }
  291.     /* Initialize the output structure.
  292.      * Since Direct3D can do rescaling for us, stick to the default
  293.      * coordinates and aspect. */
  294.     p_vout->output.i_width  = p_vout->render.i_width;
  295.     p_vout->output.i_height = p_vout->render.i_height;
  296.     p_vout->output.i_aspect = p_vout->render.i_aspect;
  297.     p_vout->fmt_out = p_vout->fmt_in;
  298.     UpdateRects( p_vout, true );
  299.     /*  create picture pool */
  300.     p_vout->output.i_chroma = 0;
  301.     i_ret = Direct3DVoutCreatePictures(p_vout, 1);
  302.     if( VLC_SUCCESS != i_ret )
  303.     {
  304.         msg_Err(p_vout, "Direct3D picture pool initialization failed !");
  305.         return i_ret;
  306.     }
  307.     /* create scene */
  308.     i_ret = Direct3DVoutCreateScene(p_vout);
  309.     if( VLC_SUCCESS != i_ret )
  310.     {
  311.         msg_Err(p_vout, "Direct3D scene initialization failed !");
  312.         Direct3DVoutReleasePictures(p_vout);
  313.         return i_ret;
  314.     }
  315.     /* Change the window title bar text */
  316.     PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
  317.     p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
  318.     return VLC_SUCCESS;
  319. }
  320. /*****************************************************************************
  321.  * End: terminate Sys video thread output method
  322.  *****************************************************************************
  323.  * Terminate an output method created by Create.
  324.  * It is called at the end of the thread.
  325.  *****************************************************************************/
  326. static void End( vout_thread_t *p_vout )
  327. {
  328.     Direct3DVoutReleaseScene(p_vout);
  329.     Direct3DVoutReleasePictures(p_vout);
  330.     Direct3DVoutClose( p_vout );
  331. }
  332. /*****************************************************************************
  333.  * Manage: handle Sys events
  334.  *****************************************************************************
  335.  * This function should be called regularly by the video output thread.
  336.  * It returns a non null value if an error occurred.
  337.  *****************************************************************************/
  338. static int Manage( vout_thread_t *p_vout )
  339. {
  340.     /* If we do not control our window, we check for geometry changes
  341.      * ourselves because the parent might not send us its events. */
  342.     vlc_mutex_lock( &p_vout->p_sys->lock );
  343.     if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
  344.     {
  345.         RECT rect_parent;
  346.         POINT point;
  347.         vlc_mutex_unlock( &p_vout->p_sys->lock );
  348.         GetClientRect( p_vout->p_sys->hparent, &rect_parent );
  349.         point.x = point.y = 0;
  350.         ClientToScreen( p_vout->p_sys->hparent, &point );
  351.         OffsetRect( &rect_parent, point.x, point.y );
  352.         if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
  353.         {
  354.             p_vout->p_sys->rect_parent = rect_parent;
  355.             SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
  356.                           rect_parent.right - rect_parent.left,
  357.                           rect_parent.bottom - rect_parent.top,
  358.                           SWP_NOZORDER );
  359.         }
  360.     }
  361.     else
  362.     {
  363.         vlc_mutex_unlock( &p_vout->p_sys->lock );
  364.     }
  365.     /*
  366.      * Position Change
  367.      */
  368.     if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
  369.     {
  370. #if 0 /* need that when bicubic filter is available */
  371.         RECT rect;
  372.         UINT width, height;
  373.         GetClientRect(p_vout->p_sys->hvideownd, &rect);
  374.         width  = rect.right-rect.left;
  375.         height = rect.bottom-rect.top;
  376.         if( (width != p_vout->p_sys->d3dpp.BackBufferWidth)
  377.          || (height != p_vout->p_sys->d3dpp.BackBufferHeight) )
  378.         {
  379.             msg_Dbg(p_vout, "resizing device back buffers to (%lux%lu)", width, height);
  380.             // need to reset D3D device to resize back buffer
  381.             if( VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, width, height) )
  382.                 return VLC_EGENERIC;
  383.         }
  384. #endif
  385.         p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
  386.     }
  387.     /* autoscale toggle */
  388.     if( p_vout->i_changes & VOUT_SCALE_CHANGE )
  389.     {
  390.         p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
  391.         p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
  392.         p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
  393.         UpdateRects( p_vout, true );
  394.     }
  395.     /* scaling factor */
  396.     if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
  397.     {
  398.         p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
  399.         p_vout->b_autoscale = false;
  400.         p_vout->i_zoom =
  401.             (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
  402.         UpdateRects( p_vout, true );
  403.     }
  404.     /* Check for cropping / aspect changes */
  405.     if( p_vout->i_changes & VOUT_CROP_CHANGE ||
  406.         p_vout->i_changes & VOUT_ASPECT_CHANGE )
  407.     {
  408.         p_vout->i_changes &= ~VOUT_CROP_CHANGE;
  409.         p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
  410.         p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
  411.         p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
  412.         p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
  413.         p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
  414.         p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
  415.         p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
  416.         p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
  417.         p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
  418.         UpdateRects( p_vout, true );
  419.     }
  420.     /* We used to call the Win32 PeekMessage function here to read the window
  421.      * messages. But since window can stay blocked into this function for a
  422.      * long time (for example when you move your window on the screen), I
  423.      * decided to isolate PeekMessage in another thread. */
  424.     /*
  425.      * Fullscreen change
  426.      */
  427.     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
  428.         || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
  429.     {
  430.         Win32ToggleFullscreen( p_vout );
  431.         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
  432.         p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
  433.     }
  434.     /*
  435.      * Pointer change
  436.      */
  437.     if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
  438.         (mdate() - p_vout->p_sys->i_lastmoved) >
  439.             p_vout->p_sys->i_mouse_hide_timeout )
  440.     {
  441.         POINT point;
  442.         HWND hwnd;
  443.         /* Hide the cursor only if it is inside our window */
  444.         GetCursorPos( &point );
  445.         hwnd = WindowFromPoint(point);
  446.         if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
  447.         {
  448.             PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
  449.         }
  450.         else
  451.         {
  452.             p_vout->p_sys->i_lastmoved = mdate();
  453.         }
  454.     }
  455.     /*
  456.      * "Always on top" status change
  457.      */
  458.     if( p_vout->p_sys->b_on_top_change )
  459.     {
  460.         vlc_value_t val;
  461.         HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
  462.         var_Get( p_vout, "video-on-top", &val );
  463.         /* Set the window on top if necessary */
  464.         if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
  465.                            & WS_EX_TOPMOST ) )
  466.         {
  467.             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
  468.                            MF_BYCOMMAND | MFS_CHECKED );
  469.             SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
  470.                           SWP_NOSIZE | SWP_NOMOVE );
  471.         }
  472.         else
  473.         /* The window shouldn't be on top */
  474.         if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
  475.                            & WS_EX_TOPMOST ) )
  476.         {
  477.             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
  478.                            MF_BYCOMMAND | MFS_UNCHECKED );
  479.             SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
  480.                           SWP_NOSIZE | SWP_NOMOVE );
  481.         }
  482.         p_vout->p_sys->b_on_top_change = false;
  483.     }
  484.     /* Check if the event thread is still running */
  485.     if( !vlc_object_alive (p_vout->p_sys->p_event) )
  486.     {
  487.         return VLC_EGENERIC; /* exit */
  488.     }
  489.     return VLC_SUCCESS;
  490. }
  491. /*****************************************************************************
  492.  * Display: displays previously rendered output
  493.  *****************************************************************************
  494.  * This function sends the currently rendered image to the display, wait until
  495.  * it is displayed and switch the two rendering buffers, preparing next frame.
  496.  *****************************************************************************/
  497. static void Display( vout_thread_t *p_vout, picture_t *p_pic )
  498. {
  499.     LPDIRECT3DDEVICE9       p_d3ddev = p_vout->p_sys->p_d3ddev;
  500.     // Present the back buffer contents to the display
  501.     // No stretching should happen here !
  502.     RECT src = p_vout->p_sys->rect_dest_clipped;
  503.     RECT dst = p_vout->p_sys->rect_dest_clipped;
  504.     HRESULT hr = IDirect3DDevice9_Present(p_d3ddev, &src, &dst,
  505.                                           NULL, NULL);
  506.     if( FAILED(hr) )
  507.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  508. }
  509. /*
  510. ** this function is only used once when the first picture is received
  511. ** this function will show the video window once a picture is ready
  512. */
  513. static void FirstDisplay( vout_thread_t *p_vout, picture_t *p_pic )
  514. {
  515.     /* get initial picture presented through D3D */
  516.     Display(p_vout, p_pic);
  517.     /*
  518.     ** Video window is initially hidden, show it now since we got a
  519.     ** picture to show.
  520.     */
  521.     SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
  522.         SWP_ASYNCWINDOWPOS|
  523.         SWP_FRAMECHANGED|
  524.         SWP_SHOWWINDOW|
  525.         SWP_NOMOVE|
  526.         SWP_NOSIZE|
  527.         SWP_NOZORDER );
  528.     /* use and restores proper display function for further pictures */
  529.     p_vout->pf_display = Display;
  530. }
  531. /*****************************************************************************
  532.  * DirectD3DVoutCreate: Initialize and instance of Direct3D9
  533.  *****************************************************************************
  534.  * This function initialize Direct3D and analyze available resources from
  535.  * default adapter.
  536.  *****************************************************************************/
  537. static int Direct3DVoutCreate( vout_thread_t *p_vout )
  538. {
  539.     HRESULT hr;
  540.     LPDIRECT3D9 p_d3dobj;
  541.     D3DCAPS9 d3dCaps;
  542.     LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
  543.     p_vout->p_sys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
  544.     if( NULL == p_vout->p_sys->hd3d9_dll )
  545.     {
  546.         msg_Warn( p_vout, "cannot load d3d9.dll, aborting" );
  547.         return VLC_EGENERIC;
  548.     }
  549.     OurDirect3DCreate9 =
  550.       (void *)GetProcAddress( p_vout->p_sys->hd3d9_dll,
  551.                               TEXT("Direct3DCreate9") );
  552.     if( OurDirect3DCreate9 == NULL )
  553.     {
  554.         msg_Err( p_vout, "Cannot locate reference to Direct3DCreate9 ABI in DLL" );
  555.         return VLC_EGENERIC;
  556.     }
  557.     /* Create the D3D object. */
  558.     p_d3dobj = OurDirect3DCreate9( D3D_SDK_VERSION );
  559.     if( NULL == p_d3dobj )
  560.     {
  561.        msg_Err( p_vout, "Could not create Direct3D9 instance.");
  562.        return VLC_EGENERIC;
  563.     }
  564.     p_vout->p_sys->p_d3dobj = p_d3dobj;
  565.     /*
  566.     ** Get device capabilities
  567.     */
  568.     ZeroMemory(&d3dCaps, sizeof(d3dCaps));
  569.     hr = IDirect3D9_GetDeviceCaps(p_d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps);
  570.     if( FAILED(hr) )
  571.     {
  572.        msg_Err( p_vout, "Could not read adapter capabilities. (hr=0x%lX)", hr);
  573.        return VLC_EGENERIC;
  574.     }
  575.     /* TODO: need to test device capabilities and select the right render function */
  576.     return VLC_SUCCESS;
  577. }
  578. /*****************************************************************************
  579.  * DirectD3DVoutRelease: release an instance of Direct3D9
  580.  *****************************************************************************/
  581. static void Direct3DVoutRelease( vout_thread_t *p_vout )
  582. {
  583.     if( p_vout->p_sys->p_d3dobj )
  584.     {
  585.        IDirect3D9_Release(p_vout->p_sys->p_d3dobj);
  586.        p_vout->p_sys->p_d3dobj = NULL;
  587.     }
  588.     if( NULL != p_vout->p_sys->hd3d9_dll )
  589.     {
  590.         FreeLibrary(p_vout->p_sys->hd3d9_dll);
  591.         p_vout->p_sys->hd3d9_dll = NULL;
  592.     }
  593. }
  594. static int Direct3DFillPresentationParameters(vout_thread_t *p_vout)
  595. {
  596.     LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
  597.     D3DDISPLAYMODE d3ddm;
  598.     HRESULT hr;
  599.     /*
  600.     ** Get the current desktop display mode, so we can set up a back
  601.     ** buffer of the same format
  602.     */
  603.     hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
  604.     if( FAILED(hr))
  605.     {
  606.        msg_Err( p_vout, "Could not read adapter display mode. (hr=0x%lX)", hr);
  607.        return VLC_EGENERIC;
  608.     }
  609.     /* Set up the structure used to create the D3DDevice. */
  610.     D3DPRESENT_PARAMETERS *d3dpp = &p_vout->p_sys->d3dpp;
  611.     ZeroMemory( d3dpp, sizeof(D3DPRESENT_PARAMETERS) );
  612.     d3dpp->Flags                  = D3DPRESENTFLAG_VIDEO;
  613.     d3dpp->Windowed               = TRUE;
  614.     d3dpp->hDeviceWindow          = p_vout->p_sys->hvideownd;
  615.     d3dpp->BackBufferWidth        = d3ddm.Width;
  616.     d3dpp->BackBufferHeight       = d3ddm.Height;
  617.     d3dpp->SwapEffect             = D3DSWAPEFFECT_COPY;
  618.     d3dpp->MultiSampleType        = D3DMULTISAMPLE_NONE;
  619.     d3dpp->PresentationInterval   = D3DPRESENT_INTERVAL_DEFAULT;
  620.     d3dpp->BackBufferFormat       = d3ddm.Format;
  621.     d3dpp->BackBufferCount        = 1;
  622.     d3dpp->EnableAutoDepthStencil = FALSE;
  623.     const unsigned i_adapter_count = IDirect3D9_GetAdapterCount(p_d3dobj);
  624.     for( unsigned i = 1; i < i_adapter_count; i++ )
  625.     {
  626.         hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, i, &d3ddm );
  627.         if( FAILED(hr) )
  628.             continue;
  629.         d3dpp->BackBufferWidth  = __MAX(d3dpp->BackBufferWidth,  d3ddm.Width);
  630.         d3dpp->BackBufferHeight = __MAX(d3dpp->BackBufferHeight, d3ddm.Height);
  631.     }
  632.     RECT *display = &p_vout->p_sys->rect_display;
  633.     display->left   = 0;
  634.     display->top    = 0;
  635.     display->right  = d3dpp->BackBufferWidth;
  636.     display->bottom = d3dpp->BackBufferHeight;
  637.     return VLC_SUCCESS;
  638. }
  639. /*****************************************************************************
  640.  * DirectD3DVoutOpen: Takes care of all the Direct3D9 initialisations
  641.  *****************************************************************************
  642.  * This function creates Direct3D device
  643.  * this must be called from the vout thread for performance reason, as
  644.  * all Direct3D Device APIs are used in a non multithread safe environment
  645.  *****************************************************************************/
  646. static int Direct3DVoutOpen( vout_thread_t *p_vout )
  647. {
  648.     LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
  649.     LPDIRECT3DDEVICE9 p_d3ddev;
  650.     HRESULT hr;
  651.     if( VLC_SUCCESS != Direct3DFillPresentationParameters(p_vout) )
  652.         return VLC_EGENERIC;
  653.     // Create the D3DDevice
  654.     hr = IDirect3D9_CreateDevice(p_d3dobj, D3DADAPTER_DEFAULT,
  655.                                  D3DDEVTYPE_HAL, p_vout->p_sys->hvideownd,
  656.                                  D3DCREATE_SOFTWARE_VERTEXPROCESSING|
  657.                                  D3DCREATE_MULTITHREADED,
  658.                                  &p_vout->p_sys->d3dpp, &p_d3ddev );
  659.     if( FAILED(hr) )
  660.     {
  661.        msg_Err(p_vout, "Could not create the D3D device! (hr=0x%lX)", hr);
  662.        return VLC_EGENERIC;
  663.     }
  664.     p_vout->p_sys->p_d3ddev = p_d3ddev;
  665.     msg_Dbg( p_vout, "Direct3D device adapter successfully initialized" );
  666.     return VLC_SUCCESS;
  667. }
  668. /*****************************************************************************
  669.  * DirectD3DClose: release the Direct3D9 device
  670.  *****************************************************************************/
  671. static void Direct3DVoutClose( vout_thread_t *p_vout )
  672. {
  673.     if( p_vout->p_sys->p_d3ddev )
  674.     {
  675.        IDirect3DDevice9_Release(p_vout->p_sys->p_d3ddev);
  676.        p_vout->p_sys->p_d3ddev = NULL;
  677.     }
  678.     p_vout->p_sys->hmonitor = NULL;
  679. }
  680. /*****************************************************************************
  681.  * DirectD3DClose: reset the Direct3D9 device
  682.  *****************************************************************************
  683.  * All resources must be deallocated before the reset occur, they will be
  684.  * realllocated once the reset has been performed successfully
  685.  *****************************************************************************/
  686. static int Direct3DVoutResetDevice( vout_thread_t *p_vout )
  687. {
  688.     LPDIRECT3DDEVICE9       p_d3ddev = p_vout->p_sys->p_d3ddev;
  689.     HRESULT hr;
  690.     if( VLC_SUCCESS != Direct3DFillPresentationParameters(p_vout) )
  691.         return VLC_EGENERIC;
  692.     // release all D3D objects
  693.     Direct3DVoutReleaseScene( p_vout );
  694.     Direct3DVoutReleasePictures( p_vout );
  695.     hr = IDirect3DDevice9_Reset(p_d3ddev, &p_vout->p_sys->d3dpp);
  696.     if( SUCCEEDED(hr) )
  697.     {
  698.         // re-create them
  699.         if( (VLC_SUCCESS != Direct3DVoutCreatePictures(p_vout, 1))
  700.          || (VLC_SUCCESS != Direct3DVoutCreateScene(p_vout)) )
  701.         {
  702.             msg_Dbg(p_vout, "%s failed !", __FUNCTION__);
  703.             return VLC_EGENERIC;
  704.         }
  705.     }
  706.     else {
  707.         msg_Err(p_vout, "%s failed ! (hr=%08lX)", __FUNCTION__, hr);
  708.         return VLC_EGENERIC;
  709.     }
  710.     return VLC_SUCCESS;
  711. }
  712. static D3DFORMAT Direct3DVoutSelectFormat( vout_thread_t *p_vout, D3DFORMAT target,
  713.     const D3DFORMAT *formats, size_t count)
  714. {
  715.     LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
  716.     size_t c;
  717.     for( c=0; c<count; ++c )
  718.     {
  719.         HRESULT hr;
  720.         D3DFORMAT format = formats[c];
  721.         /* test whether device can create a surface of that format */
  722.         hr = IDirect3D9_CheckDeviceFormat(p_d3dobj, D3DADAPTER_DEFAULT,
  723.                 D3DDEVTYPE_HAL, target, 0, D3DRTYPE_SURFACE, format);
  724.         if( SUCCEEDED(hr) )
  725.         {
  726.             /* test whether device can perform color-conversion
  727.             ** from that format to target format
  728.             */
  729.             hr = IDirect3D9_CheckDeviceFormatConversion(p_d3dobj,
  730.                     D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
  731.                     format, target);
  732.         }
  733.         if( SUCCEEDED(hr) )
  734.         {
  735.             // found a compatible format
  736.             switch( format )
  737.             {
  738.                 case D3DFMT_UYVY:
  739.                     msg_Dbg( p_vout, "selected surface pixel format is UYVY");
  740.                     break;
  741.                 case D3DFMT_YUY2:
  742.                     msg_Dbg( p_vout, "selected surface pixel format is YUY2");
  743.                     break;
  744.                 case D3DFMT_X8R8G8B8:
  745.                     msg_Dbg( p_vout, "selected surface pixel format is X8R8G8B8");
  746.                     break;
  747.                 case D3DFMT_A8R8G8B8:
  748.                     msg_Dbg( p_vout, "selected surface pixel format is A8R8G8B8");
  749.                     break;
  750.                 case D3DFMT_R8G8B8:
  751.                     msg_Dbg( p_vout, "selected surface pixel format is R8G8B8");
  752.                     break;
  753.                 case D3DFMT_R5G6B5:
  754.                     msg_Dbg( p_vout, "selected surface pixel format is R5G6B5");
  755.                     break;
  756.                 case D3DFMT_X1R5G5B5:
  757.                     msg_Dbg( p_vout, "selected surface pixel format is X1R5G5B5");
  758.                     break;
  759.                 default:
  760.                     msg_Dbg( p_vout, "selected surface pixel format is 0x%0X", format);
  761.                     break;
  762.             }
  763.             return format;
  764.         }
  765.         else if( D3DERR_NOTAVAILABLE != hr )
  766.         {
  767.             msg_Err( p_vout, "Could not query adapter supported formats. (hr=0x%lX)", hr);
  768.             break;
  769.         }
  770.     }
  771.     return D3DFMT_UNKNOWN;
  772. }
  773. static D3DFORMAT Direct3DVoutFindFormat(vout_thread_t *p_vout, int i_chroma, D3DFORMAT target)
  774. {
  775.     //if( p_vout->p_sys->b_hw_yuv && ! _got_vista_or_above )
  776.     if( p_vout->p_sys->b_hw_yuv )
  777.     {
  778.     /* it sounds like vista does not support YUV surfaces at all */
  779.         switch( i_chroma )
  780.         {
  781.             case VLC_FOURCC('U','Y','V','Y'):
  782.             case VLC_FOURCC('U','Y','N','V'):
  783.             case VLC_FOURCC('Y','4','2','2'):
  784.             {
  785.                 static const D3DFORMAT formats[] =
  786.                     { D3DFMT_UYVY, D3DFMT_YUY2, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
  787.                 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
  788.             }
  789.             case VLC_FOURCC('I','4','2','0'):
  790.             case VLC_FOURCC('I','4','2','2'):
  791.             case VLC_FOURCC('Y','V','1','2'):
  792.             {
  793.                 /* typically 3D textures don't support planar format
  794.                 ** fallback to packed version and use CPU for the conversion
  795.                 */
  796.                 static const D3DFORMAT formats[] =
  797.                     { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
  798.                 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
  799.             }
  800.             case VLC_FOURCC('Y','U','Y','2'):
  801.             case VLC_FOURCC('Y','U','N','V'):
  802.             {
  803.                 static const D3DFORMAT formats[] =
  804.                     { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
  805.                 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
  806.             }
  807.         }
  808.     }
  809.     switch( i_chroma )
  810.     {
  811.         case VLC_FOURCC('R', 'V', '1', '5'):
  812.         {
  813.             static const D3DFORMAT formats[] =
  814.                 { D3DFMT_X1R5G5B5 };
  815.             return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
  816.         }
  817.         case VLC_FOURCC('R', 'V', '1', '6'):
  818.         {
  819.             static const D3DFORMAT formats[] =
  820.                 { D3DFMT_R5G6B5 };
  821.             return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
  822.         }
  823.         case VLC_FOURCC('R', 'V', '2', '4'):
  824.         {
  825.             static const D3DFORMAT formats[] =
  826.                 { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
  827.             return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
  828.         }
  829.         case VLC_FOURCC('R', 'V', '3', '2'):
  830.         {
  831.             static const D3DFORMAT formats[] =
  832.                 { D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8 };
  833.             return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
  834.         }
  835.         default:
  836.         {
  837.             /* use display default format */
  838.             LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
  839.             D3DDISPLAYMODE d3ddm;
  840.             HRESULT hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
  841.             if( SUCCEEDED(hr))
  842.             {
  843.                 /*
  844.                 ** some professional cards could use some advanced pixel format as default,
  845.                 ** make sure we stick with chromas that we can handle internally
  846.                 */
  847.                 switch( d3ddm.Format )
  848.                 {
  849.                     case D3DFMT_R8G8B8:
  850.                     case D3DFMT_X8R8G8B8:
  851.                     case D3DFMT_A8R8G8B8:
  852.                     case D3DFMT_R5G6B5:
  853.                     case D3DFMT_X1R5G5B5:
  854.                         msg_Dbg( p_vout, "defaulting to adapter pixel format");
  855.                         return Direct3DVoutSelectFormat(p_vout, target, &d3ddm.Format, 1);
  856.                     default:
  857.                     {
  858.                         /* if we fall here, that probably means that we need to render some YUV format */
  859.                         static const D3DFORMAT formats[] =
  860.                             { D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
  861.                         msg_Dbg( p_vout, "defaulting to built-in pixel format");
  862.                         return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
  863.                     }
  864.                 }
  865.             }
  866.         }
  867.     }
  868.     return D3DFMT_UNKNOWN;
  869. }
  870. static int Direct3DVoutSetOutputFormat(vout_thread_t *p_vout, D3DFORMAT format)
  871. {
  872.     switch( format )
  873.     {
  874.         case D3DFMT_YUY2:
  875.             p_vout->output.i_chroma = VLC_FOURCC('Y', 'U', 'Y', '2');
  876.             break;
  877.         case D3DFMT_UYVY:
  878.             p_vout->output.i_chroma = VLC_FOURCC('U', 'Y', 'V', 'Y');
  879.             break;
  880.         case D3DFMT_R8G8B8:
  881.             p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '2', '4');
  882.             p_vout->output.i_rmask = 0xff0000;
  883.             p_vout->output.i_gmask = 0x00ff00;
  884.             p_vout->output.i_bmask = 0x0000ff;
  885.             break;
  886.         case D3DFMT_X8R8G8B8:
  887.         case D3DFMT_A8R8G8B8:
  888.             p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '3', '2');
  889.             p_vout->output.i_rmask = 0x00ff0000;
  890.             p_vout->output.i_gmask = 0x0000ff00;
  891.             p_vout->output.i_bmask = 0x000000ff;
  892.             break;
  893.         case D3DFMT_R5G6B5:
  894.             p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '6');
  895.             p_vout->output.i_rmask = (0x1fL)<<11;
  896.             p_vout->output.i_gmask = (0x3fL)<<5;
  897.             p_vout->output.i_bmask = (0x1fL)<<0;
  898.             break;
  899.         case D3DFMT_X1R5G5B5:
  900.             p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '5');
  901.             p_vout->output.i_rmask = (0x1fL)<<10;
  902.             p_vout->output.i_gmask = (0x1fL)<<5;
  903.             p_vout->output.i_bmask = (0x1fL)<<0;
  904.             break;
  905.         default:
  906.             return VLC_EGENERIC;
  907.     }
  908.     return VLC_SUCCESS;
  909. }
  910. /*****************************************************************************
  911.  * Direct3DVoutCreatePictures: allocate a vector of identical pictures
  912.  *****************************************************************************
  913.  * Each picture has an associated offscreen surface in video memory
  914.  * depending on hardware capabilities the picture chroma will be as close
  915.  * as possible to the orginal render chroma to reduce CPU conversion overhead
  916.  * and delegate this work to video card GPU
  917.  *****************************************************************************/
  918. static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics )
  919. {
  920.     LPDIRECT3DDEVICE9       p_d3ddev  = p_vout->p_sys->p_d3ddev;
  921.     D3DFORMAT               format;
  922.     HRESULT hr;
  923.     size_t c;
  924.     // if vout is already running, use current chroma, otherwise choose from upstream
  925.     int i_chroma = p_vout->output.i_chroma ? p_vout->output.i_chroma
  926.                                            : p_vout->render.i_chroma;
  927.     I_OUTPUTPICTURES = 0;
  928.     /*
  929.     ** find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
  930.     ** the requested chroma which is usable by the hardware in an offscreen surface, as they
  931.     ** typically support more formats than textures
  932.     */
  933.     format = Direct3DVoutFindFormat(p_vout, i_chroma, p_vout->p_sys->d3dpp.BackBufferFormat);
  934.     if( VLC_SUCCESS != Direct3DVoutSetOutputFormat(p_vout, format) )
  935.     {
  936.         msg_Err(p_vout, "surface pixel format is not supported.");
  937.         return VLC_EGENERIC;
  938.     }
  939.     for( c=0; c<i_num_pics; )
  940.     {
  941.         LPDIRECT3DSURFACE9 p_d3dsurf;
  942.         picture_t *p_pic = p_vout->p_picture+c;
  943.         hr = IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3ddev,
  944.                 p_vout->render.i_width,
  945.                 p_vout->render.i_height,
  946.                 format,
  947.                 D3DPOOL_DEFAULT,
  948.                 &p_d3dsurf,
  949.                 NULL);
  950.         if( FAILED(hr) )
  951.         {
  952.             msg_Err(p_vout, "Failed to create picture surface. (hr=0x%lx)", hr);
  953.             Direct3DVoutReleasePictures(p_vout);
  954.             return VLC_EGENERIC;
  955.         }
  956.         /* fill surface with black color */
  957.         IDirect3DDevice9_ColorFill(p_d3ddev, p_d3dsurf, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
  958.         /* assign surface to internal structure */
  959.         p_pic->p_sys = (void *)p_d3dsurf;
  960.         /* Now that we've got our direct-buffer, we can finish filling in the
  961.          * picture_t structures */
  962.         switch( p_vout->output.i_chroma )
  963.         {
  964.             case VLC_FOURCC('R','G','B','2'):
  965.                 p_pic->p->i_lines = p_vout->output.i_height;
  966.                 p_pic->p->i_visible_lines = p_vout->output.i_height;
  967.                 p_pic->p->i_pixel_pitch = 1;
  968.                 p_pic->p->i_visible_pitch = p_vout->output.i_width *
  969.                     p_pic->p->i_pixel_pitch;
  970.                 p_pic->i_planes = 1;
  971.             break;
  972.             case VLC_FOURCC('R','V','1','5'):
  973.             case VLC_FOURCC('R','V','1','6'):
  974.                 p_pic->p->i_lines = p_vout->output.i_height;
  975.                 p_pic->p->i_visible_lines = p_vout->output.i_height;
  976.                 p_pic->p->i_pixel_pitch = 2;
  977.                 p_pic->p->i_visible_pitch = p_vout->output.i_width *
  978.                     p_pic->p->i_pixel_pitch;
  979.                 p_pic->i_planes = 1;
  980.             break;
  981.             case VLC_FOURCC('R','V','2','4'):
  982.                 p_pic->p->i_lines = p_vout->output.i_height;
  983.                 p_pic->p->i_visible_lines = p_vout->output.i_height;
  984.                 p_pic->p->i_pixel_pitch = 3;
  985.                 p_pic->p->i_visible_pitch = p_vout->output.i_width *
  986.                     p_pic->p->i_pixel_pitch;
  987.                 p_pic->i_planes = 1;
  988.             break;
  989.             case VLC_FOURCC('R','V','3','2'):
  990.                 p_pic->p->i_lines = p_vout->output.i_height;
  991.                 p_pic->p->i_visible_lines = p_vout->output.i_height;
  992.                 p_pic->p->i_pixel_pitch = 4;
  993.                 p_pic->p->i_visible_pitch = p_vout->output.i_width *
  994.                     p_pic->p->i_pixel_pitch;
  995.                 p_pic->i_planes = 1;
  996.                 break;
  997.             case VLC_FOURCC('U','Y','V','Y'):
  998.             case VLC_FOURCC('Y','U','Y','2'):
  999.                 p_pic->p->i_lines = p_vout->output.i_height;
  1000.                 p_pic->p->i_visible_lines = p_vout->output.i_height;
  1001.                 p_pic->p->i_pixel_pitch = 2;
  1002.                 p_pic->p->i_visible_pitch = p_vout->output.i_width *
  1003.                     p_pic->p->i_pixel_pitch;
  1004.                 p_pic->i_planes = 1;
  1005.                 break;
  1006.             default:
  1007.                 Direct3DVoutReleasePictures(p_vout);
  1008.                 return VLC_EGENERIC;
  1009.         }
  1010.         p_pic->i_status = DESTROYED_PICTURE;
  1011.         p_pic->i_type   = DIRECT_PICTURE;
  1012.         p_pic->b_slow   = true;
  1013.         p_pic->pf_lock  = Direct3DVoutLockSurface;
  1014.         p_pic->pf_unlock = Direct3DVoutUnlockSurface;
  1015.         PP_OUTPUTPICTURE[c] = p_pic;
  1016.         I_OUTPUTPICTURES = ++c;
  1017.     }
  1018.     msg_Dbg( p_vout, "%u Direct3D pictures created successfully", c );
  1019.     return VLC_SUCCESS;
  1020. }
  1021. /*****************************************************************************
  1022.  * Direct3DVoutReleasePictures: destroy a picture vector
  1023.  *****************************************************************************
  1024.  * release all video resources used for pictures
  1025.  *****************************************************************************/
  1026. static void Direct3DVoutReleasePictures( vout_thread_t *p_vout)
  1027. {
  1028.     size_t i_num_pics = I_OUTPUTPICTURES;
  1029.     size_t c;
  1030.     for( c=0; c<i_num_pics; ++c )
  1031.     {
  1032.         picture_t *p_pic = p_vout->p_picture+c;
  1033.         if( p_pic->p_sys )
  1034.         {
  1035.             LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
  1036.             p_pic->p_sys = NULL;
  1037.             if( p_d3dsurf )
  1038.             {
  1039.                 IDirect3DSurface9_Release(p_d3dsurf);
  1040.             }
  1041.         }
  1042.     }
  1043.     msg_Dbg( p_vout, "%u Direct3D pictures released.", c);
  1044.     I_OUTPUTPICTURES = 0;
  1045. }
  1046. /*****************************************************************************
  1047.  * Direct3DVoutLockSurface: Lock surface and get picture data pointer
  1048.  *****************************************************************************
  1049.  * This function locks a surface and get the surface descriptor which amongst
  1050.  * other things has the pointer to the picture data.
  1051.  *****************************************************************************/
  1052. static int Direct3DVoutLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
  1053. {
  1054.     HRESULT hr;
  1055.     D3DLOCKED_RECT d3drect;
  1056.     LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
  1057.     if( NULL == p_d3dsurf )
  1058.         return VLC_EGENERIC;
  1059.     /* Lock the surface to get a valid pointer to the picture buffer */
  1060.     hr = IDirect3DSurface9_LockRect(p_d3dsurf, &d3drect, NULL, 0);
  1061.     if( FAILED(hr) )
  1062.     {
  1063.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1064.         return VLC_EGENERIC;
  1065.     }
  1066.     /* fill in buffer info in first plane */
  1067.     p_pic->p->p_pixels = d3drect.pBits;
  1068.     p_pic->p->i_pitch  = d3drect.Pitch;
  1069.     return VLC_SUCCESS;
  1070. }
  1071. /*****************************************************************************
  1072.  * Direct3DVoutUnlockSurface: Unlock a surface locked by Direct3DLockSurface().
  1073.  *****************************************************************************/
  1074. static int Direct3DVoutUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
  1075. {
  1076.     HRESULT hr;
  1077.     LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
  1078.     if( NULL == p_d3dsurf )
  1079.         return VLC_EGENERIC;
  1080.     /* Unlock the Surface */
  1081.     hr = IDirect3DSurface9_UnlockRect(p_d3dsurf);
  1082.     if( FAILED(hr) )
  1083.     {
  1084.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1085.         return VLC_EGENERIC;
  1086.     }
  1087.     return VLC_SUCCESS;
  1088. }
  1089. /*****************************************************************************
  1090.  * Direct3DVoutCreateScene: allocate and initialize a 3D scene
  1091.  *****************************************************************************
  1092.  * for advanced blending/filtering a texture needs be used in a 3D scene.
  1093.  *****************************************************************************/
  1094. static int Direct3DVoutCreateScene( vout_thread_t *p_vout )
  1095. {
  1096.     LPDIRECT3DDEVICE9       p_d3ddev  = p_vout->p_sys->p_d3ddev;
  1097.     LPDIRECT3DTEXTURE9      p_d3dtex;
  1098.     LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
  1099.     HRESULT hr;
  1100.     /*
  1101.     ** Create a texture for use when rendering a scene
  1102.     ** for performance reason, texture format is identical to backbuffer
  1103.     ** which would usually be a RGB format
  1104.     */
  1105.     hr = IDirect3DDevice9_CreateTexture(p_d3ddev,
  1106.             p_vout->p_sys->d3dpp.BackBufferWidth,
  1107.             p_vout->p_sys->d3dpp.BackBufferHeight,
  1108.             1,
  1109.             D3DUSAGE_RENDERTARGET,
  1110.             p_vout->p_sys->d3dpp.BackBufferFormat,
  1111.             D3DPOOL_DEFAULT,
  1112.             &p_d3dtex,
  1113.             NULL);
  1114.     if( FAILED(hr))
  1115.     {
  1116.         msg_Err(p_vout, "Failed to create texture. (hr=0x%lx)", hr);
  1117.         return VLC_EGENERIC;
  1118.     }
  1119.     /*
  1120.     ** Create a vertex buffer for use when rendering scene
  1121.     */
  1122.     hr = IDirect3DDevice9_CreateVertexBuffer(p_d3ddev,
  1123.             sizeof(CUSTOMVERTEX)*4,
  1124.             D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
  1125.             D3DFVF_CUSTOMVERTEX,
  1126.             D3DPOOL_DEFAULT,
  1127.             &p_d3dvtc,
  1128.             NULL);
  1129.     if( FAILED(hr) )
  1130.     {
  1131.         msg_Err(p_vout, "Failed to create vertex buffer. (hr=0x%lx)", hr);
  1132.             IDirect3DTexture9_Release(p_d3dtex);
  1133.         return VLC_EGENERIC;
  1134.     }
  1135.     p_vout->p_sys->p_d3dtex = p_d3dtex;
  1136.     p_vout->p_sys->p_d3dvtc = p_d3dvtc;
  1137.     // Texture coordinates outside the range [0.0, 1.0] are set
  1138.     // to the texture color at 0.0 or 1.0, respectively.
  1139.     IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
  1140.     IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
  1141.     // Set linear filtering quality
  1142.     IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  1143.     IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  1144.     // set maximum ambient light
  1145.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
  1146.     // Turn off culling
  1147.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_CULLMODE, D3DCULL_NONE);
  1148.     // Turn off the zbuffer
  1149.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ZENABLE, D3DZB_FALSE);
  1150.     // Turn off lights
  1151.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_LIGHTING, FALSE);
  1152.     // Enable dithering
  1153.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DITHERENABLE, TRUE);
  1154.     // disable stencil
  1155.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_STENCILENABLE, FALSE);
  1156.     // manage blending
  1157.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
  1158.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
  1159.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
  1160.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHATESTENABLE,TRUE);
  1161.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAREF, 0x10);
  1162.     IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER);
  1163.     // Set texture states
  1164.     IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE);
  1165.     IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
  1166.     IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
  1167.     // turn off alpha operation
  1168.     IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  1169.     msg_Dbg( p_vout, "Direct3D scene created successfully");
  1170.     return VLC_SUCCESS;
  1171. }
  1172. /*****************************************************************************
  1173.  * Direct3DVoutReleaseScene
  1174.  *****************************************************************************/
  1175. static void Direct3DVoutReleaseScene( vout_thread_t *p_vout )
  1176. {
  1177.     LPDIRECT3DTEXTURE9      p_d3dtex = p_vout->p_sys->p_d3dtex;
  1178.     LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
  1179.     if( p_d3dvtc )
  1180.     {
  1181.         IDirect3DVertexBuffer9_Release(p_d3dvtc);
  1182.         p_vout->p_sys->p_d3dvtc = NULL;
  1183.     }
  1184.     if( p_d3dtex )
  1185.     {
  1186.         IDirect3DTexture9_Release(p_d3dtex);
  1187.         p_vout->p_sys->p_d3dtex = NULL;
  1188.     }
  1189.     msg_Dbg( p_vout, "Direct3D scene released successfully");
  1190. }
  1191. /*****************************************************************************
  1192.  * Render: copy picture surface into a texture and render into a scene
  1193.  *****************************************************************************
  1194.  * This function is intented for higher end 3D cards, with pixel shader support
  1195.  * and at least 64 MB of video RAM.
  1196.  *****************************************************************************/
  1197. static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic )
  1198. {
  1199.     LPDIRECT3DDEVICE9       p_d3ddev  = p_vout->p_sys->p_d3ddev;
  1200.     LPDIRECT3DTEXTURE9      p_d3dtex;
  1201.     LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
  1202.     LPDIRECT3DSURFACE9      p_d3dsrc, p_d3ddest;
  1203.     CUSTOMVERTEX            *p_vertices;
  1204.     HRESULT hr;
  1205.     float f_width, f_height;
  1206.     // check if device is still available
  1207.     hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
  1208.     if( FAILED(hr) )
  1209.     {
  1210.         if( (D3DERR_DEVICENOTRESET != hr)
  1211.          || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout)) )
  1212.         {
  1213.             // device is not usable at present (lost device, out of video mem ?)
  1214.             return;
  1215.         }
  1216.     }
  1217.     p_d3dtex  = p_vout->p_sys->p_d3dtex;
  1218.     p_d3dvtc  = p_vout->p_sys->p_d3dvtc;
  1219.     /* Clear the backbuffer and the zbuffer */
  1220.     hr = IDirect3DDevice9_Clear( p_d3ddev, 0, NULL, D3DCLEAR_TARGET,
  1221.                               D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0 );
  1222.     if( FAILED(hr) )
  1223.     {
  1224.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1225.         return;
  1226.     }
  1227.     /*  retrieve picture surface */
  1228.     p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
  1229.     if( NULL == p_d3dsrc )
  1230.     {
  1231.         msg_Dbg( p_vout, "no surface to render ?");
  1232.         return;
  1233.     }
  1234.     /* retrieve texture top-level surface */
  1235.     hr = IDirect3DTexture9_GetSurfaceLevel(p_d3dtex, 0, &p_d3ddest);
  1236.     if( FAILED(hr) )
  1237.     {
  1238.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1239.         return;
  1240.     }
  1241.     /* Copy picture surface into texture surface
  1242.      * color space conversion and scaling happen here */
  1243.     RECT src = p_vout->p_sys->rect_src_clipped;
  1244.     RECT dst = p_vout->p_sys->rect_dest_clipped;
  1245.     hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, &src, p_d3ddest, &dst, D3DTEXF_LINEAR);
  1246.     IDirect3DSurface9_Release(p_d3ddest);
  1247.     if( FAILED(hr) )
  1248.     {
  1249.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1250.         return;
  1251.     }
  1252.     /* Update the vertex buffer */
  1253.     hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (VOID **)(&p_vertices), D3DLOCK_DISCARD);
  1254.     if( FAILED(hr) )
  1255.     {
  1256.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1257.         return;
  1258.     }
  1259.     /* Setup vertices */
  1260.     f_width  = (float)p_vout->p_sys->d3dpp.BackBufferWidth;
  1261.     f_height = (float)p_vout->p_sys->d3dpp.BackBufferHeight;
  1262.     /* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */
  1263.     /* http://www.sjbrown.co.uk/2003/05/01/fix-directx-rasterisation/ */
  1264.     p_vertices[0].x       = -0.5f;       // left
  1265.     p_vertices[0].y       = -0.5f;       // top
  1266.     p_vertices[0].z       = 0.0f;
  1267.     p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
  1268.     p_vertices[0].rhw     = 1.0f;
  1269.     p_vertices[0].tu      = 0.0f;
  1270.     p_vertices[0].tv      = 0.0f;
  1271.     p_vertices[1].x       = f_width - 0.5f;    // right
  1272.     p_vertices[1].y       = -0.5f;       // top
  1273.     p_vertices[1].z       = 0.0f;
  1274.     p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
  1275.     p_vertices[1].rhw     = 1.0f;
  1276.     p_vertices[1].tu      = 1.0f;
  1277.     p_vertices[1].tv      = 0.0f;
  1278.     p_vertices[2].x       = f_width - 0.5f;    // right
  1279.     p_vertices[2].y       = f_height - 0.5f;   // bottom
  1280.     p_vertices[2].z       = 0.0f;
  1281.     p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
  1282.     p_vertices[2].rhw     = 1.0f;
  1283.     p_vertices[2].tu      = 1.0f;
  1284.     p_vertices[2].tv      = 1.0f;
  1285.     p_vertices[3].x       = -0.5f;       // left
  1286.     p_vertices[3].y       = f_height - 0.5f;   // bottom
  1287.     p_vertices[3].z       = 0.0f;
  1288.     p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
  1289.     p_vertices[3].rhw     = 1.0f;
  1290.     p_vertices[3].tu      = 0.0f;
  1291.     p_vertices[3].tv      = 1.0f;
  1292.     hr= IDirect3DVertexBuffer9_Unlock(p_d3dvtc);
  1293.     if( FAILED(hr) )
  1294.     {
  1295.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1296.         return;
  1297.     }
  1298.     // Begin the scene
  1299.     hr = IDirect3DDevice9_BeginScene(p_d3ddev);
  1300.     if( FAILED(hr) )
  1301.     {
  1302.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1303.         return;
  1304.     }
  1305.     // Setup our texture. Using textures introduces the texture stage states,
  1306.     // which govern how textures get blended together (in the case of multiple
  1307.     // textures) and lighting information. In this case, we are modulating
  1308.     // (blending) our texture with the diffuse color of the vertices.
  1309.     hr = IDirect3DDevice9_SetTexture(p_d3ddev, 0, (LPDIRECT3DBASETEXTURE9)p_d3dtex);
  1310.     if( FAILED(hr) )
  1311.     {
  1312.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1313.         IDirect3DDevice9_EndScene(p_d3ddev);
  1314.         return;
  1315.     }
  1316.     // Render the vertex buffer contents
  1317.     hr = IDirect3DDevice9_SetStreamSource(p_d3ddev, 0, p_d3dvtc, 0, sizeof(CUSTOMVERTEX));
  1318.     if( FAILED(hr) )
  1319.     {
  1320.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1321.         IDirect3DDevice9_EndScene(p_d3ddev);
  1322.         return;
  1323.     }
  1324.     // we use FVF instead of vertex shader
  1325.     hr = IDirect3DDevice9_SetFVF(p_d3ddev, D3DFVF_CUSTOMVERTEX);
  1326.     if( FAILED(hr) )
  1327.     {
  1328.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1329.         IDirect3DDevice9_EndScene(p_d3ddev);
  1330.         return;
  1331.     }
  1332.     // draw rectangle
  1333.     hr = IDirect3DDevice9_DrawPrimitive(p_d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
  1334.     if( FAILED(hr) )
  1335.     {
  1336.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1337.         IDirect3DDevice9_EndScene(p_d3ddev);
  1338.         return;
  1339.     }
  1340.     // End the scene
  1341.     hr = IDirect3DDevice9_EndScene(p_d3ddev);
  1342.     if( FAILED(hr) )
  1343.     {
  1344.         msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
  1345.         return;
  1346.     }
  1347. }