1 /*****************************************************************************
2 * direct3d.c: Windows Direct3D video output module
3 *****************************************************************************
4 * Copyright (C) 2006 the VideoLAN team
7 * Authors: Damien Fouilleul <damienf@videolan.org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
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.
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.
35 *****************************************************************************/
36 #include <errno.h> /* ENOMEM */
37 #include <stdlib.h> /* free() */
38 #include <string.h> /* strerror() */
41 #include <vlc_interface.h>
42 #include <vlc_playlist.h>
50 /*****************************************************************************
52 *****************************************************************************/
53 static int OpenVideo ( vlc_object_t * );
54 static void CloseVideo ( vlc_object_t * );
56 static int Init ( vout_thread_t * );
57 static void End ( vout_thread_t * );
58 static int Manage ( vout_thread_t * );
59 static void Display ( vout_thread_t *, picture_t * );
60 static void FirstDisplay( vout_thread_t *, picture_t * );
62 static int Direct3DVoutCreate ( vout_thread_t * );
63 static void Direct3DVoutRelease ( vout_thread_t * );
65 static int Direct3DVoutOpen ( vout_thread_t * );
66 static void Direct3DVoutClose ( vout_thread_t * );
68 static int Direct3DVoutResetDevice( vout_thread_t * );
70 static int Direct3DVoutCreatePictures ( vout_thread_t *, size_t );
71 static void Direct3DVoutReleasePictures ( vout_thread_t * );
73 static int Direct3DVoutLockSurface ( vout_thread_t *, picture_t * );
74 static int Direct3DVoutUnlockSurface( vout_thread_t *, picture_t * );
76 static int Direct3DVoutCreateScene ( vout_thread_t * );
77 static void Direct3DVoutReleaseScene ( vout_thread_t * );
78 static void Direct3DVoutRenderScene ( vout_thread_t *, picture_t * );
80 /*****************************************************************************
82 *****************************************************************************/
84 static vlc_bool_t _got_vista_or_above;
86 static int get_capability_for_osversion(void)
89 winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
91 if( GetVersionEx(&winVer) )
93 if( winVer.dwMajorVersion > 5 )
95 /* Windows Vista or above, make this module the default */
96 _got_vista_or_above = VLC_TRUE;
100 /* Windows XP or lower, make sure this module isn't the default */
101 _got_vista_or_above = VLC_FALSE;
106 set_shortname( "Direct3D" );
107 set_category( CAT_VIDEO );
108 set_subcategory( SUBCAT_VIDEO_VOUT );
109 set_description( _("DirectX 3D video output") );
110 set_capability( "video output", get_capability_for_osversion() );
111 add_shortcut( "direct3d" );
112 set_callbacks( OpenVideo, CloseVideo );
114 /* FIXME: Hack to avoid unregistering our window class */
115 linked_with_a_crap_library_which_uses_atexit( );
119 /* check if we registered a window class because we need to
122 if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
123 UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
126 /*****************************************************************************
128 *****************************************************************************
129 *****************************************************************************/
132 FLOAT x,y,z; // vertex untransformed position
133 FLOAT rhw; // eye distance
134 D3DCOLOR diffuse; // diffuse color
135 FLOAT tu, tv; // texture relative coordinates
138 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
140 /*****************************************************************************
141 * OpenVideo: allocate DirectX video thread output method
142 *****************************************************************************
143 * This function allocates and initialize the Direct3D vout method.
144 *****************************************************************************/
145 static int OpenVideo( vlc_object_t *p_this )
147 vout_thread_t * p_vout = (vout_thread_t *)p_this;
150 /* Allocate structure */
151 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
152 if( p_vout->p_sys == NULL )
154 msg_Err( p_vout, "out of memory" );
157 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
159 if( VLC_SUCCESS != Direct3DVoutCreate( p_vout ) )
161 msg_Err( p_vout, "Direct3D could not be initialized !");
165 /* Initialisations */
166 p_vout->pf_init = Init;
167 p_vout->pf_end = End;
168 p_vout->pf_manage = Manage;
169 p_vout->pf_render = Direct3DVoutRenderScene;
170 p_vout->pf_display = FirstDisplay;
172 p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
173 p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
174 p_vout->p_sys->i_changes = 0;
175 p_vout->p_sys->b_wallpaper = 0;
176 vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
177 SetRectEmpty( &p_vout->p_sys->rect_display );
178 SetRectEmpty( &p_vout->p_sys->rect_parent );
180 var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
181 var_Create( p_vout, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
182 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
183 var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
185 p_vout->p_sys->b_cursor_hidden = 0;
186 p_vout->p_sys->i_lastmoved = mdate();
188 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
189 var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
191 /* Set main window's size */
192 p_vout->p_sys->i_window_width = p_vout->i_window_width;
193 p_vout->p_sys->i_window_height = p_vout->i_window_height;
195 /* Create the DirectXEventThread, this thread is created by us to isolate
196 * the Win32 PeekMessage function calls. We want to do this because
197 * Windows can stay blocked inside this call for a long time, and when
198 * this happens it thus blocks vlc's video_output thread.
199 * DirectXEventThread will take care of the creation of the video
200 * window (because PeekMessage has to be called from the same thread which
201 * created the window). */
202 msg_Dbg( p_vout, "creating DirectXEventThread" );
203 p_vout->p_sys->p_event =
204 vlc_object_create( p_vout, sizeof(event_thread_t) );
205 p_vout->p_sys->p_event->p_vout = p_vout;
206 if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
207 E_(DirectXEventThread), 0, 1 ) )
209 msg_Err( p_vout, "cannot create DirectXEventThread" );
210 vlc_object_destroy( p_vout->p_sys->p_event );
211 p_vout->p_sys->p_event = NULL;
215 if( p_vout->p_sys->p_event->b_error )
217 msg_Err( p_vout, "DirectXEventThread failed" );
221 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
223 msg_Dbg( p_vout, "DirectXEventThread running" );
225 /* Variable to indicate if the window should be on top of others */
226 /* Trigger a callback right now */
227 var_Get( p_vout, "video-on-top", &val );
228 var_Set( p_vout, "video-on-top", val );
230 /* disable screensaver by temporarily changing system settings */
231 p_vout->p_sys->i_spi_lowpowertimeout = 0;
232 p_vout->p_sys->i_spi_powerofftimeout = 0;
233 p_vout->p_sys->i_spi_screensavetimeout = 0;
234 var_Get( p_vout, "disable-screensaver", &val);
236 msg_Dbg(p_vout, "disabling screen saver");
237 SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
238 0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
239 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
240 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
242 SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
243 &(p_vout->p_sys->i_spi_powerofftimeout), 0);
244 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
245 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
247 SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
248 &(p_vout->p_sys->i_spi_screensavetimeout), 0);
249 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
250 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
256 CloseVideo( VLC_OBJECT(p_vout) );
260 /*****************************************************************************
261 * CloseVideo: destroy Sys video thread output method
262 *****************************************************************************
263 * Terminate an output method created by Create
264 *****************************************************************************/
265 static void CloseVideo( vlc_object_t *p_this )
267 vout_thread_t * p_vout = (vout_thread_t *)p_this;
269 Direct3DVoutRelease( p_vout );
271 if( p_vout->p_sys->p_event )
273 vlc_object_detach( p_vout->p_sys->p_event );
275 /* Kill DirectXEventThread */
276 p_vout->p_sys->p_event->b_die = VLC_TRUE;
278 /* we need to be sure DirectXEventThread won't stay stuck in
279 * GetMessage, so we send a fake message */
280 if( p_vout->p_sys->hwnd )
282 PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
285 vlc_thread_join( p_vout->p_sys->p_event );
286 vlc_object_destroy( p_vout->p_sys->p_event );
289 vlc_mutex_destroy( &p_vout->p_sys->lock );
291 /* restore screensaver system settings */
292 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
293 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
294 p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
296 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
297 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
298 p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
300 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
301 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
302 p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
307 free( p_vout->p_sys );
308 p_vout->p_sys = NULL;
312 /*****************************************************************************
313 * Init: initialize Direct3D video thread output method
314 *****************************************************************************/
315 static int Init( vout_thread_t *p_vout )
320 var_Get( p_vout, "directx-hw-yuv", &val );
321 p_vout->p_sys->b_hw_yuv = val.b_bool;
323 /* Initialise Direct3D */
324 if( VLC_SUCCESS != Direct3DVoutOpen( p_vout ) )
326 msg_Err( p_vout, "cannot initialize Direct3D" );
330 /* Initialize the output structure.
331 * Since Direct3D can do rescaling for us, stick to the default
332 * coordinates and aspect. */
333 p_vout->output.i_width = p_vout->render.i_width;
334 p_vout->output.i_height = p_vout->render.i_height;
335 p_vout->output.i_aspect = p_vout->render.i_aspect;
336 p_vout->fmt_out = p_vout->fmt_in;
337 E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
339 /* create picture pool */
340 i_ret = Direct3DVoutCreatePictures(p_vout, 1);
341 if( VLC_SUCCESS != i_ret )
343 msg_Err(p_vout, "Direct3D picture pool initialization failed !");
348 i_ret = Direct3DVoutCreateScene(p_vout);
349 if( VLC_SUCCESS != i_ret )
351 msg_Err(p_vout, "Direct3D scene initialization failed !");
352 Direct3DVoutReleasePictures(p_vout);
356 /* Change the window title bar text */
357 PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
359 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
363 /*****************************************************************************
364 * End: terminate Sys video thread output method
365 *****************************************************************************
366 * Terminate an output method created by Create.
367 * It is called at the end of the thread.
368 *****************************************************************************/
369 static void End( vout_thread_t *p_vout )
371 Direct3DVoutReleaseScene(p_vout);
372 Direct3DVoutReleasePictures(p_vout);
373 Direct3DVoutClose( p_vout );
376 /*****************************************************************************
377 * Manage: handle Sys events
378 *****************************************************************************
379 * This function should be called regularly by the video output thread.
380 * It returns a non null value if an error occurred.
381 *****************************************************************************/
382 static int Manage( vout_thread_t *p_vout )
384 /* If we do not control our window, we check for geometry changes
385 * ourselves because the parent might not send us its events. */
386 vlc_mutex_lock( &p_vout->p_sys->lock );
387 if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
392 vlc_mutex_unlock( &p_vout->p_sys->lock );
394 GetClientRect( p_vout->p_sys->hparent, &rect_parent );
395 point.x = point.y = 0;
396 ClientToScreen( p_vout->p_sys->hparent, &point );
397 OffsetRect( &rect_parent, point.x, point.y );
399 if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
401 p_vout->p_sys->rect_parent = rect_parent;
403 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
404 rect_parent.right - rect_parent.left,
405 rect_parent.bottom - rect_parent.top,
411 vlc_mutex_unlock( &p_vout->p_sys->lock );
417 if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
419 #if 0 /* need that when bicubic filter is available */
423 GetClientRect(p_vout->p_sys->hvideownd, &rect);
424 width = rect.right-rect.left;
425 height = rect.bottom-rect.top;
427 if( (width != p_vout->p_sys->d3dpp.BackBufferWidth)
428 || (height != p_vout->p_sys->d3dpp.BackBufferHeight) )
430 msg_Dbg(p_vout, "resizing device back buffers to (%lux%lu)", width, height);
431 // need to reset D3D device to resize back buffer
432 if( VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, width, height) )
436 p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
439 /* Check for cropping / aspect changes */
440 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
441 p_vout->i_changes & VOUT_ASPECT_CHANGE )
443 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
444 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
446 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
447 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
448 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
449 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
450 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
451 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
452 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
453 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
454 E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
457 /* We used to call the Win32 PeekMessage function here to read the window
458 * messages. But since window can stay blocked into this function for a
459 * long time (for example when you move your window on the screen), I
460 * decided to isolate PeekMessage in another thread. */
465 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
466 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
468 Win32ToggleFullscreen( p_vout );
470 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
471 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
477 if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
478 (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 )
483 /* Hide the cursor only if it is inside our window */
484 GetCursorPos( &point );
485 hwnd = WindowFromPoint(point);
486 if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
488 PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
492 p_vout->p_sys->i_lastmoved = mdate();
497 * "Always on top" status change
499 if( p_vout->p_sys->b_on_top_change )
502 HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
504 var_Get( p_vout, "video-on-top", &val );
506 /* Set the window on top if necessary */
507 if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
510 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
511 MF_BYCOMMAND | MFS_CHECKED );
512 SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
513 SWP_NOSIZE | SWP_NOMOVE );
516 /* The window shouldn't be on top */
517 if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
520 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
521 MF_BYCOMMAND | MFS_UNCHECKED );
522 SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
523 SWP_NOSIZE | SWP_NOMOVE );
526 p_vout->p_sys->b_on_top_change = VLC_FALSE;
529 /* Check if the event thread is still running */
530 if( p_vout->p_sys->p_event->b_die )
532 return VLC_EGENERIC; /* exit */
538 /*****************************************************************************
539 * Display: displays previously rendered output
540 *****************************************************************************
541 * This function sends the currently rendered image to the display, wait until
542 * it is displayed and switch the two rendering buffers, preparing next frame.
543 *****************************************************************************/
544 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
546 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
547 // Present the back buffer contents to the display
548 // stretching and filtering happens here
549 HRESULT hr = IDirect3DDevice9_Present(p_d3ddev,
550 &(p_vout->p_sys->rect_src_clipped),
553 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
557 ** this function is only used once when the first picture is received
558 ** this function will show the video window once a picture is ready
561 static void FirstDisplay( vout_thread_t *p_vout, picture_t *p_pic )
563 /* get initial picture presented through D3D */
564 Display(p_vout, p_pic);
567 ** Video window is initially hidden, show it now since we got a
570 SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
578 /* use and restores proper display function for further pictures */
579 p_vout->pf_display = Display;
582 /*****************************************************************************
583 * DirectD3DVoutCreate: Initialize and instance of Direct3D9
584 *****************************************************************************
585 * This function initialize Direct3D and analyze available resources from
587 *****************************************************************************/
588 static int Direct3DVoutCreate( vout_thread_t *p_vout )
591 LPDIRECT3D9 p_d3dobj;
594 LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
596 p_vout->p_sys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
597 if( NULL == p_vout->p_sys->hd3d9_dll )
599 msg_Warn( p_vout, "cannot load d3d9.dll, aborting" );
604 (void *)GetProcAddress( p_vout->p_sys->hd3d9_dll,
605 TEXT("Direct3DCreate9") );
606 if( OurDirect3DCreate9 == NULL )
608 msg_Err( p_vout, "Cannot locate reference to Direct3DCreate9 ABI in DLL" );
612 /* Create the D3D object. */
613 p_d3dobj = OurDirect3DCreate9( D3D_SDK_VERSION );
614 if( NULL == p_d3dobj )
616 msg_Err( p_vout, "Could not create Direct3D9 instance.");
619 p_vout->p_sys->p_d3dobj = p_d3dobj;
622 ** Get device capabilities
624 ZeroMemory(&d3dCaps, sizeof(d3dCaps));
625 hr = IDirect3D9_GetDeviceCaps(p_d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps);
628 msg_Err( p_vout, "Could not read adapter capabilities. (hr=0x%lX)", hr);
631 /* TODO: need to test device capabilities and select the right render function */
636 /*****************************************************************************
637 * DirectD3DVoutRelease: release an instance of Direct3D9
638 *****************************************************************************/
640 static void Direct3DVoutRelease( vout_thread_t *p_vout )
642 if( p_vout->p_sys->p_d3dobj )
644 IDirect3D9_Release(p_vout->p_sys->p_d3dobj);
645 p_vout->p_sys->p_d3dobj = NULL;
647 if( NULL != p_vout->p_sys->hd3d9_dll )
649 FreeLibrary(p_vout->p_sys->hd3d9_dll);
650 p_vout->p_sys->hd3d9_dll = NULL;
654 static int Direct3DFillPresentationParameters(vout_thread_t *p_vout, D3DPRESENT_PARAMETERS *d3dpp)
656 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
657 D3DDISPLAYMODE d3ddm;
661 ** Get the current desktop display mode, so we can set up a back
662 ** buffer of the same format
664 hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
667 msg_Err( p_vout, "Could not read adapter display mode. (hr=0x%lX)", hr);
671 /* keep a copy of current desktop format */
672 p_vout->p_sys->bbFormat = d3ddm.Format;
674 /* Set up the structure used to create the D3DDevice. */
675 ZeroMemory( d3dpp, sizeof(D3DPRESENT_PARAMETERS) );
676 d3dpp->Flags = D3DPRESENTFLAG_VIDEO;
677 d3dpp->Windowed = TRUE;
678 d3dpp->hDeviceWindow = p_vout->p_sys->hvideownd;
679 d3dpp->BackBufferWidth = p_vout->output.i_width;
680 d3dpp->BackBufferHeight = p_vout->output.i_height;
681 d3dpp->SwapEffect = D3DSWAPEFFECT_COPY;
682 d3dpp->MultiSampleType = D3DMULTISAMPLE_NONE;
683 d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
684 d3dpp->BackBufferFormat = d3ddm.Format;
685 d3dpp->BackBufferCount = 1;
686 d3dpp->EnableAutoDepthStencil = FALSE;
691 /*****************************************************************************
692 * DirectD3DVoutOpen: Takes care of all the Direct3D9 initialisations
693 *****************************************************************************
694 * This function creates Direct3D device
695 * this must be called from the vout thread for performance reason, as
696 * all Direct3D Device APIs are used in a non multithread safe environment
697 *****************************************************************************/
698 static int Direct3DVoutOpen( vout_thread_t *p_vout )
700 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
701 LPDIRECT3DDEVICE9 p_d3ddev;
702 D3DPRESENT_PARAMETERS d3dpp;
705 if( VLC_SUCCESS != Direct3DFillPresentationParameters(p_vout, &d3dpp) )
708 // Create the D3DDevice
709 hr = IDirect3D9_CreateDevice(p_d3dobj, D3DADAPTER_DEFAULT,
710 D3DDEVTYPE_HAL, p_vout->p_sys->hvideownd,
711 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
715 msg_Err(p_vout, "Could not create the D3D device! (hr=0x%lX)", hr);
718 p_vout->p_sys->p_d3ddev = p_d3ddev;
720 msg_Dbg( p_vout, "Direct3D device adapter successfully initialized" );
724 /*****************************************************************************
725 * DirectD3DClose: release the Direct3D9 device
726 *****************************************************************************/
727 static void Direct3DVoutClose( vout_thread_t *p_vout )
729 if( p_vout->p_sys->p_d3ddev )
731 IDirect3DDevice9_Release(p_vout->p_sys->p_d3ddev);
732 p_vout->p_sys->p_d3ddev = NULL;
735 p_vout->p_sys->hmonitor = NULL;
738 /*****************************************************************************
739 * DirectD3DClose: reset the Direct3D9 device
740 *****************************************************************************
741 * All resources must be deallocated before the reset occur, they will be
742 * realllocated once the reset has been performed successfully
743 *****************************************************************************/
744 static int Direct3DVoutResetDevice( vout_thread_t *p_vout )
746 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
747 D3DPRESENT_PARAMETERS d3dpp;
750 if( VLC_SUCCESS != Direct3DFillPresentationParameters(p_vout, &d3dpp) )
753 // release all D3D objects
754 Direct3DVoutReleaseScene( p_vout );
755 Direct3DVoutReleasePictures( p_vout );
757 hr = IDirect3DDevice9_Reset(p_d3ddev, &d3dpp);
761 if( (VLC_SUCCESS != Direct3DVoutCreatePictures(p_vout, 1))
762 || (VLC_SUCCESS != Direct3DVoutCreateScene(p_vout)) )
764 msg_Dbg(p_vout, "%s failed !", __FUNCTION__);
769 msg_Err(p_vout, "%s failed ! (hr=%08lX)", __FUNCTION__, hr);
775 static D3DFORMAT Direct3DVoutSelectFormat( vout_thread_t *p_vout, D3DFORMAT target,
776 const D3DFORMAT *formats, size_t count)
778 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
781 for( c=0; c<count; ++c )
784 D3DFORMAT format = formats[c];
785 /* test whether device can create a surface of that format */
786 hr = IDirect3D9_CheckDeviceFormat(p_d3dobj, D3DADAPTER_DEFAULT,
787 D3DDEVTYPE_HAL, target, 0, D3DRTYPE_SURFACE, format);
790 /* test whether device can perform color-conversion
791 ** from that format to target format
793 hr = IDirect3D9_CheckDeviceFormatConversion(p_d3dobj,
794 D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
799 // found a compatible format
803 msg_Dbg( p_vout, "selected surface pixel format is UYVY");
806 msg_Dbg( p_vout, "selected surface pixel format is YUY2");
808 case D3DFMT_X8R8G8B8:
809 msg_Dbg( p_vout, "selected surface pixel format is X8R8G8B8");
811 case D3DFMT_A8R8G8B8:
812 msg_Dbg( p_vout, "selected surface pixel format is A8R8G8B8");
815 msg_Dbg( p_vout, "selected surface pixel format is R8G8B8");
818 msg_Dbg( p_vout, "selected surface pixel format is R5G6B5");
820 case D3DFMT_X1R5G5B5:
821 msg_Dbg( p_vout, "selected surface pixel format is X1R5G5B5");
824 msg_Dbg( p_vout, "selected surface pixel format is 0x%0X", format);
829 else if( D3DERR_NOTAVAILABLE != hr )
831 msg_Err( p_vout, "Could not query adapter supported formats. (hr=0x%lX)", hr);
835 return D3DFMT_UNKNOWN;
838 static D3DFORMAT Direct3DVoutFindFormat(vout_thread_t *p_vout, int i_chroma, D3DFORMAT target)
840 if( p_vout->p_sys->b_hw_yuv && ! _got_vista_or_above )
842 /* it sounds like vista does not support YUV surfaces at all */
845 case VLC_FOURCC('U','Y','V','Y'):
846 case VLC_FOURCC('U','Y','N','V'):
847 case VLC_FOURCC('Y','4','2','2'):
849 static const D3DFORMAT formats[] =
850 { D3DFMT_UYVY, D3DFMT_YUY2, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
851 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
853 case VLC_FOURCC('I','4','2','0'):
854 case VLC_FOURCC('I','4','2','2'):
855 case VLC_FOURCC('Y','V','1','2'):
857 /* typically 3D textures don't support planar format
858 ** fallback to packed version and use CPU for the conversion
860 static const D3DFORMAT formats[] =
861 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
862 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
864 case VLC_FOURCC('Y','U','Y','2'):
865 case VLC_FOURCC('Y','U','N','V'):
867 static const D3DFORMAT formats[] =
868 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
869 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
876 case VLC_FOURCC('R', 'V', '1', '5'):
878 static const D3DFORMAT formats[] =
880 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
882 case VLC_FOURCC('R', 'V', '1', '6'):
884 static const D3DFORMAT formats[] =
886 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
888 case VLC_FOURCC('R', 'V', '2', '4'):
890 static const D3DFORMAT formats[] =
891 { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
892 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
894 case VLC_FOURCC('R', 'V', '3', '2'):
896 static const D3DFORMAT formats[] =
897 { D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8 };
898 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
902 /* use display default format */
903 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
904 D3DDISPLAYMODE d3ddm;
906 HRESULT hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
910 ** some professional cards could use some advanced pixel format as default,
911 ** make sure we stick with chromas that we can handle internally
913 switch( d3ddm.Format )
916 case D3DFMT_X8R8G8B8:
917 case D3DFMT_A8R8G8B8:
918 msg_Dbg( p_vout, "defaulting to adpater pixel format");
919 return Direct3DVoutSelectFormat(p_vout, target, &d3ddm.Format, 1);
922 /* if we fall here, that probably means that we need to render some YUV format */
923 static const D3DFORMAT formats[] =
924 { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
925 msg_Dbg( p_vout, "defaulting to built-in pixel format");
926 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
932 return D3DFMT_UNKNOWN;
935 static int Direct3DVoutSetOutputFormat(vout_thread_t *p_vout, D3DFORMAT format)
940 p_vout->output.i_chroma = VLC_FOURCC('Y', 'U', 'Y', '2');
943 p_vout->output.i_chroma = VLC_FOURCC('U', 'Y', 'V', 'Y');
946 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '2', '4');
948 case D3DFMT_X8R8G8B8:
949 case D3DFMT_A8R8G8B8:
950 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '3', '2');
951 p_vout->output.i_rmask = 0x00ff0000;
952 p_vout->output.i_gmask = 0x0000ff00;
953 p_vout->output.i_bmask = 0x000000ff;
954 # if defined( WORDS_BIGENDIAN )
955 p_vout->output.i_rrshift = 0;
956 p_vout->output.i_lrshift = 24;
957 p_vout->output.i_rgshift = 0;
958 p_vout->output.i_lgshift = 16;
959 p_vout->output.i_rbshift = 0;
960 p_vout->output.i_lbshift = 8;
962 p_vout->output.i_rrshift = 0;
963 p_vout->output.i_lrshift = 8;
964 p_vout->output.i_rgshift = 0;
965 p_vout->output.i_lgshift = 16;
966 p_vout->output.i_rbshift = 0;
967 p_vout->output.i_lbshift = 24;
971 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '6');
972 p_vout->output.i_rmask = (0x1fL)<<11;
973 p_vout->output.i_gmask = (0x3fL)<<5;
974 p_vout->output.i_bmask = (0x1fL)<<0;
975 # if defined( WORDS_BIGENDIAN )
976 p_vout->output.i_rrshift = 0;
977 p_vout->output.i_lrshift = 11;
978 p_vout->output.i_rgshift = 0;
979 p_vout->output.i_lgshift = 5;
980 p_vout->output.i_rbshift = 0;
981 p_vout->output.i_lbshift = 0;
983 /* FIXME: since components are not byte aligned,
984 there is no chance that this will work */
985 p_vout->output.i_rrshift = 0;
986 p_vout->output.i_lrshift = 0;
987 p_vout->output.i_rgshift = 0;
988 p_vout->output.i_lgshift = 5;
989 p_vout->output.i_rbshift = 0;
990 p_vout->output.i_lbshift = 11;
993 case D3DFMT_X1R5G5B5:
994 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '5');
995 p_vout->output.i_rmask = (0x1fL)<<10;
996 p_vout->output.i_gmask = (0x1fL)<<5;
997 p_vout->output.i_bmask = (0x1fL)<<0;
998 # if defined( WORDS_BIGENDIAN )
999 p_vout->output.i_rrshift = 0;
1000 p_vout->output.i_lrshift = 10;
1001 p_vout->output.i_rgshift = 0;
1002 p_vout->output.i_lgshift = 5;
1003 p_vout->output.i_rbshift = 0;
1004 p_vout->output.i_lbshift = 0;
1006 /* FIXME: since components are not byte aligned,
1007 there is no chance that this will work */
1008 p_vout->output.i_rrshift = 0;
1009 p_vout->output.i_lrshift = 1;
1010 p_vout->output.i_rgshift = 0;
1011 p_vout->output.i_lgshift = 5;
1012 p_vout->output.i_rbshift = 0;
1013 p_vout->output.i_lbshift = 11;
1017 return VLC_EGENERIC;
1022 /*****************************************************************************
1023 * Direct3DVoutCreatePictures: allocate a vector of identical pictures
1024 *****************************************************************************
1025 * Each picture has an associated offscreen surface in video memory
1026 * depending on hardware capabilities the picture chroma will be as close
1027 * as possible to the orginal render chroma to reduce CPU conversion overhead
1028 * and delegate this work to video card GPU
1029 *****************************************************************************/
1030 static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics )
1032 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1037 I_OUTPUTPICTURES = 0;
1040 ** find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
1041 ** the requested chroma which is usable by the hardware in an offscreen surface, as they
1042 ** typically support more formats than textures
1044 format = Direct3DVoutFindFormat(p_vout, p_vout->render.i_chroma, p_vout->p_sys->bbFormat);
1045 if( VLC_SUCCESS != Direct3DVoutSetOutputFormat(p_vout, format) )
1047 msg_Err(p_vout, "surface pixel format is not supported.");
1048 return VLC_EGENERIC;
1051 for( c=0; c<i_num_pics; )
1054 LPDIRECT3DSURFACE9 p_d3dsurf;
1055 picture_t *p_pic = p_vout->p_picture+c;
1057 hr = IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3ddev,
1058 p_vout->render.i_width,
1059 p_vout->render.i_height,
1066 msg_Err(p_vout, "Failed to create picture surface. (hr=0x%lx)", hr);
1067 Direct3DVoutReleasePictures(p_vout);
1068 return VLC_EGENERIC;
1071 /* fill surface with black color */
1072 IDirect3DDevice9_ColorFill(p_d3ddev, p_d3dsurf, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
1074 /* assign surface to internal structure */
1075 p_pic->p_sys = (void *)p_d3dsurf;
1077 /* Now that we've got our direct-buffer, we can finish filling in the
1078 * picture_t structures */
1079 switch( p_vout->output.i_chroma )
1081 case VLC_FOURCC('R','G','B','2'):
1082 p_pic->p->i_lines = p_vout->output.i_height;
1083 p_pic->p->i_visible_lines = p_vout->output.i_height;
1084 p_pic->p->i_pixel_pitch = 1;
1085 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1086 p_pic->p->i_pixel_pitch;
1087 p_pic->i_planes = 1;
1089 case VLC_FOURCC('R','V','1','5'):
1090 case VLC_FOURCC('R','V','1','6'):
1091 p_pic->p->i_lines = p_vout->output.i_height;
1092 p_pic->p->i_visible_lines = p_vout->output.i_height;
1093 p_pic->p->i_pixel_pitch = 2;
1094 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1095 p_pic->p->i_pixel_pitch;
1096 p_pic->i_planes = 1;
1098 case VLC_FOURCC('R','V','2','4'):
1099 p_pic->p->i_lines = p_vout->output.i_height;
1100 p_pic->p->i_visible_lines = p_vout->output.i_height;
1101 p_pic->p->i_pixel_pitch = 3;
1102 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1103 p_pic->p->i_pixel_pitch;
1104 p_pic->i_planes = 1;
1106 case VLC_FOURCC('R','V','3','2'):
1107 p_pic->p->i_lines = p_vout->output.i_height;
1108 p_pic->p->i_visible_lines = p_vout->output.i_height;
1109 p_pic->p->i_pixel_pitch = 4;
1110 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1111 p_pic->p->i_pixel_pitch;
1112 p_pic->i_planes = 1;
1114 case VLC_FOURCC('U','Y','V','Y'):
1115 case VLC_FOURCC('Y','U','Y','2'):
1116 p_pic->p->i_lines = p_vout->output.i_height;
1117 p_pic->p->i_visible_lines = p_vout->output.i_height;
1118 p_pic->p->i_pixel_pitch = 2;
1119 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1120 p_pic->p->i_pixel_pitch;
1121 p_pic->i_planes = 1;
1124 Direct3DVoutReleasePictures(p_vout);
1125 return VLC_EGENERIC;
1127 p_pic->i_status = DESTROYED_PICTURE;
1128 p_pic->i_type = DIRECT_PICTURE;
1129 p_pic->b_slow = VLC_TRUE;
1130 p_pic->pf_lock = Direct3DVoutLockSurface;
1131 p_pic->pf_unlock = Direct3DVoutUnlockSurface;
1132 PP_OUTPUTPICTURE[c] = p_pic;
1134 I_OUTPUTPICTURES = ++c;
1137 msg_Dbg( p_vout, "%u Direct3D pictures created successfully", c );
1142 /*****************************************************************************
1143 * Direct3DVoutReleasePictures: destroy a picture vector
1144 *****************************************************************************
1145 * release all video resources used for pictures
1146 *****************************************************************************/
1147 static void Direct3DVoutReleasePictures( vout_thread_t *p_vout)
1149 size_t i_num_pics = I_OUTPUTPICTURES;
1151 for( c=0; c<i_num_pics; ++c )
1153 picture_t *p_pic = p_vout->p_picture+c;
1156 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1158 p_pic->p_sys = NULL;
1162 IDirect3DSurface9_Release(p_d3dsurf);
1166 msg_Dbg( p_vout, "%u Direct3D pictures released.", c);
1168 I_OUTPUTPICTURES = 0;
1171 /*****************************************************************************
1172 * Direct3DVoutLockSurface: Lock surface and get picture data pointer
1173 *****************************************************************************
1174 * This function locks a surface and get the surface descriptor which amongst
1175 * other things has the pointer to the picture data.
1176 *****************************************************************************/
1177 static int Direct3DVoutLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1180 D3DLOCKED_RECT d3drect;
1181 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1183 if( NULL == p_d3dsurf )
1184 return VLC_EGENERIC;
1186 /* Lock the surface to get a valid pointer to the picture buffer */
1187 hr = IDirect3DSurface9_LockRect(p_d3dsurf, &d3drect, NULL, 0);
1190 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1191 return VLC_EGENERIC;
1194 /* fill in buffer info in first plane */
1195 p_pic->p->p_pixels = d3drect.pBits;
1196 p_pic->p->i_pitch = d3drect.Pitch;
1201 /*****************************************************************************
1202 * Direct3DVoutUnlockSurface: Unlock a surface locked by Direct3DLockSurface().
1203 *****************************************************************************/
1204 static int Direct3DVoutUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1207 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1209 if( NULL == p_d3dsurf )
1210 return VLC_EGENERIC;
1212 /* Unlock the Surface */
1213 hr = IDirect3DSurface9_UnlockRect(p_d3dsurf);
1216 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1217 return VLC_EGENERIC;
1222 /*****************************************************************************
1223 * Direct3DVoutCreateScene: allocate and initialize a 3D scene
1224 *****************************************************************************
1225 * for advanced blending/filtering a texture needs be used in a 3D scene.
1226 *****************************************************************************/
1228 static int Direct3DVoutCreateScene( vout_thread_t *p_vout )
1230 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1231 LPDIRECT3DTEXTURE9 p_d3dtex;
1232 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
1237 ** Create a texture for use when rendering a scene
1238 ** for performance reason, texture format is identical to backbuffer
1239 ** which would usually be a RGB format
1241 hr = IDirect3DDevice9_CreateTexture(p_d3ddev,
1242 p_vout->render.i_width,
1243 p_vout->render.i_height,
1245 D3DUSAGE_RENDERTARGET,
1246 p_vout->p_sys->bbFormat,
1252 msg_Err(p_vout, "Failed to create texture. (hr=0x%lx)", hr);
1253 return VLC_EGENERIC;
1257 ** Create a vertex buffer for use when rendering scene
1259 hr = IDirect3DDevice9_CreateVertexBuffer(p_d3ddev,
1260 sizeof(CUSTOMVERTEX)*4,
1261 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
1262 D3DFVF_CUSTOMVERTEX,
1268 msg_Err(p_vout, "Failed to create vertex buffer. (hr=0x%lx)", hr);
1269 IDirect3DTexture9_Release(p_d3dtex);
1270 return VLC_EGENERIC;
1273 p_vout->p_sys->p_d3dtex = p_d3dtex;
1274 p_vout->p_sys->p_d3dvtc = p_d3dvtc;
1276 // Texture coordinates outside the range [0.0, 1.0] are set
1277 // to the texture color at 0.0 or 1.0, respectively.
1278 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1279 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1281 // Set linear filtering quality
1282 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
1283 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
1285 // set maximum ambient light
1286 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
1289 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_CULLMODE, D3DCULL_NONE);
1291 // Turn off the zbuffer
1292 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ZENABLE, D3DZB_FALSE);
1295 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_LIGHTING, FALSE);
1298 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DITHERENABLE, TRUE);
1301 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_STENCILENABLE, FALSE);
1304 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
1305 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
1306 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
1307 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHATESTENABLE,TRUE);
1308 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAREF, 0x10);
1309 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER);
1311 // Set texture states
1312 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE);
1313 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
1314 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
1316 // turn off alpha operation
1317 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
1319 msg_Dbg( p_vout, "Direct3D scene created successfully");
1324 /*****************************************************************************
1325 * Direct3DVoutReleaseScene
1326 *****************************************************************************/
1327 static void Direct3DVoutReleaseScene( vout_thread_t *p_vout )
1329 LPDIRECT3DTEXTURE9 p_d3dtex = p_vout->p_sys->p_d3dtex;
1330 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1334 IDirect3DVertexBuffer9_Release(p_d3dvtc);
1335 p_vout->p_sys->p_d3dvtc = NULL;
1340 IDirect3DTexture9_Release(p_d3dtex);
1341 p_vout->p_sys->p_d3dtex = NULL;
1343 msg_Dbg( p_vout, "Direct3D scene released successfully");
1346 /*****************************************************************************
1347 * Render: copy picture surface into a texture and render into a scene
1348 *****************************************************************************
1349 * This function is intented for higher end 3D cards, with pixel shader support
1350 * and at least 64 MB of video RAM.
1351 *****************************************************************************/
1352 static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic )
1354 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1355 LPDIRECT3DTEXTURE9 p_d3dtex;
1356 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
1357 LPDIRECT3DSURFACE9 p_d3dsrc, p_d3ddest;
1358 CUSTOMVERTEX *p_vertices;
1360 float f_width, f_height;
1362 // check if device is still available
1363 hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
1366 if( (D3DERR_DEVICENOTRESET != hr)
1367 || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout)) )
1369 // device is not usable at present (lost device, out of video mem ?)
1373 p_d3dtex = p_vout->p_sys->p_d3dtex;
1374 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1376 /* Clear the backbuffer and the zbuffer */
1377 hr = IDirect3DDevice9_Clear( p_d3ddev, 0, NULL, D3DCLEAR_TARGET,
1378 D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0 );
1381 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1385 /* retrieve picture surface */
1386 p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1387 if( NULL == p_d3dsrc )
1389 msg_Dbg( p_vout, "no surface to render ?");
1393 /* retrieve texture top-level surface */
1394 hr = IDirect3DTexture9_GetSurfaceLevel(p_d3dtex, 0, &p_d3ddest);
1397 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1401 /* Copy picture surface into texture surface, color space conversion happens here */
1402 hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, NULL, p_d3ddest, NULL, D3DTEXF_NONE);
1403 IDirect3DSurface9_Release(p_d3ddest);
1406 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1410 /* Update the vertex buffer */
1411 hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (VOID **)(&p_vertices), D3DLOCK_DISCARD);
1414 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1418 /* Setup vertices */
1419 f_width = (float)(p_vout->output.i_width);
1420 f_height = (float)(p_vout->output.i_height);
1422 p_vertices[0].x = 0.0f; // left
1423 p_vertices[0].y = 0.0f; // top
1424 p_vertices[0].z = 0.0f;
1425 p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1426 p_vertices[0].rhw = 1.0f;
1427 p_vertices[0].tu = 0.0f;
1428 p_vertices[0].tv = 0.0f;
1430 p_vertices[1].x = f_width; // right
1431 p_vertices[1].y = 0.0f; // top
1432 p_vertices[1].z = 0.0f;
1433 p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1434 p_vertices[1].rhw = 1.0f;
1435 p_vertices[1].tu = 1.0f;
1436 p_vertices[1].tv = 0.0f;
1438 p_vertices[2].x = f_width; // right
1439 p_vertices[2].y = f_height; // bottom
1440 p_vertices[2].z = 0.0f;
1441 p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1442 p_vertices[2].rhw = 1.0f;
1443 p_vertices[2].tu = 1.0f;
1444 p_vertices[2].tv = 1.0f;
1446 p_vertices[3].x = 0.0f; // left
1447 p_vertices[3].y = f_height; // bottom
1448 p_vertices[3].z = 0.0f;
1449 p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1450 p_vertices[3].rhw = 1.0f;
1451 p_vertices[3].tu = 0.0f;
1452 p_vertices[3].tv = 1.0f;
1454 hr= IDirect3DVertexBuffer9_Unlock(p_d3dvtc);
1457 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1462 hr = IDirect3DDevice9_BeginScene(p_d3ddev);
1465 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1469 // Setup our texture. Using textures introduces the texture stage states,
1470 // which govern how textures get blended together (in the case of multiple
1471 // textures) and lighting information. In this case, we are modulating
1472 // (blending) our texture with the diffuse color of the vertices.
1473 hr = IDirect3DDevice9_SetTexture(p_d3ddev, 0, (LPDIRECT3DBASETEXTURE9)p_d3dtex);
1476 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1477 IDirect3DDevice9_EndScene(p_d3ddev);
1481 // Render the vertex buffer contents
1482 hr = IDirect3DDevice9_SetStreamSource(p_d3ddev, 0, p_d3dvtc, 0, sizeof(CUSTOMVERTEX));
1485 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1486 IDirect3DDevice9_EndScene(p_d3ddev);
1490 // we use FVF instead of vertex shader
1491 hr = IDirect3DDevice9_SetVertexShader(p_d3ddev, NULL);
1494 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1495 IDirect3DDevice9_EndScene(p_d3ddev);
1499 hr = IDirect3DDevice9_SetFVF(p_d3ddev, D3DFVF_CUSTOMVERTEX);
1502 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1503 IDirect3DDevice9_EndScene(p_d3ddev);
1508 hr = IDirect3DDevice9_DrawPrimitive(p_d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
1511 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1512 IDirect3DDevice9_EndScene(p_d3ddev);
1517 hr = IDirect3DDevice9_EndScene(p_d3ddev);
1520 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);