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