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 */
42 #include <vlc_common.h>
43 #include <vlc_plugin.h>
44 #include <vlc_interface.h>
45 #include <vlc_playlist.h>
53 /*****************************************************************************
55 *****************************************************************************/
56 static int OpenVideo ( vlc_object_t * );
57 static void CloseVideo ( vlc_object_t * );
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 * );
65 static int Direct3DVoutCreate ( vout_thread_t * );
66 static void Direct3DVoutRelease ( vout_thread_t * );
68 static int Direct3DVoutOpen ( vout_thread_t * );
69 static void Direct3DVoutClose ( vout_thread_t * );
71 static int Direct3DVoutResetDevice( vout_thread_t * );
73 static int Direct3DVoutCreatePictures ( vout_thread_t *, size_t );
74 static void Direct3DVoutReleasePictures ( vout_thread_t * );
76 static int Direct3DVoutLockSurface ( vout_thread_t *, picture_t * );
77 static int Direct3DVoutUnlockSurface( vout_thread_t *, picture_t * );
79 static int Direct3DVoutCreateScene ( vout_thread_t * );
80 static void Direct3DVoutReleaseScene ( vout_thread_t * );
81 static void Direct3DVoutRenderScene ( vout_thread_t *, picture_t * );
83 /*****************************************************************************
85 *****************************************************************************/
87 static bool _got_vista_or_above;
89 static int get_capability_for_osversion(void)
92 winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
94 if( GetVersionEx(&winVer) )
96 if( winVer.dwMajorVersion > 5 )
98 /* Windows Vista or above, make this module the default */
99 _got_vista_or_above = true;
103 /* Windows XP or lower, make sure this module isn't the default */
104 _got_vista_or_above = false;
109 set_shortname( "Direct3D" )
110 set_category( CAT_VIDEO )
111 set_subcategory( SUBCAT_VIDEO_VOUT )
112 set_description( N_("DirectX 3D video output") )
113 set_capability( "video output", get_capability_for_osversion() )
114 add_shortcut( "direct3d" )
115 set_callbacks( OpenVideo, CloseVideo )
117 /* FIXME: Hack to avoid unregistering our window class */
118 linked_with_a_crap_library_which_uses_atexit ()
122 /* check if we registered a window class because we need to
125 if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
126 UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
129 /*****************************************************************************
131 *****************************************************************************
132 *****************************************************************************/
135 FLOAT x,y,z; // vertex untransformed position
136 FLOAT rhw; // eye distance
137 D3DCOLOR diffuse; // diffuse color
138 FLOAT tu, tv; // texture relative coordinates
141 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
143 /*****************************************************************************
144 * OpenVideo: allocate Vout video thread output method
145 *****************************************************************************
146 * This function allocates and initialize the Direct3D vout method.
147 *****************************************************************************/
148 static int OpenVideo( vlc_object_t *p_this )
150 vout_thread_t * p_vout = (vout_thread_t *)p_this;
153 /* Allocate structure */
154 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
155 if( p_vout->p_sys == NULL )
158 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
160 if( VLC_SUCCESS != Direct3DVoutCreate( p_vout ) )
162 msg_Err( p_vout, "Direct3D could not be initialized !");
166 /* Initialisations */
167 p_vout->pf_init = Init;
168 p_vout->pf_end = End;
169 p_vout->pf_manage = Manage;
170 p_vout->pf_render = Direct3DVoutRenderScene;
171 p_vout->pf_display = FirstDisplay;
173 p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
174 p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
175 p_vout->p_sys->i_changes = 0;
176 vlc_mutex_init( &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 );
183 p_vout->p_sys->b_cursor_hidden = 0;
184 p_vout->p_sys->i_lastmoved = mdate();
185 p_vout->p_sys->i_mouse_hide_timeout =
186 var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
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 Vout EventThread, 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 * Vout EventThread 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 Vout EventThread" );
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, "Vout Events Thread",
207 EventThread, 0, 1 ) )
209 msg_Err( p_vout, "cannot create Vout EventThread" );
210 vlc_object_release( 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, "Vout EventThread failed" );
221 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
223 msg_Dbg( p_vout, "Vout EventThread 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->b_fullscreen )
273 msg_Dbg( p_vout, "Quitting fullscreen" );
274 Win32ToggleFullscreen( p_vout );
275 /* Force fullscreen in the core for the next video */
276 var_SetBool( p_vout, "fullscreen", true );
279 if( p_vout->p_sys->p_event )
281 vlc_object_detach( p_vout->p_sys->p_event );
283 /* Kill Vout EventThread */
284 vlc_object_kill( p_vout->p_sys->p_event );
286 /* we need to be sure Vout EventThread won't stay stuck in
287 * GetMessage, so we send a fake message */
288 if( p_vout->p_sys->hwnd )
290 PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
293 vlc_thread_join( p_vout->p_sys->p_event );
294 vlc_object_release( p_vout->p_sys->p_event );
297 vlc_mutex_destroy( &p_vout->p_sys->lock );
299 /* restore screensaver system settings */
300 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
301 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
302 p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
304 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
305 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
306 p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
308 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
309 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
310 p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
313 free( p_vout->p_sys );
314 p_vout->p_sys = NULL;
317 /*****************************************************************************
318 * Init: initialize Direct3D video thread output method
319 *****************************************************************************/
320 static int Init( vout_thread_t *p_vout )
325 var_Get( p_vout, "directx-hw-yuv", &val );
326 p_vout->p_sys->b_hw_yuv = val.b_bool;
328 /* Initialise Direct3D */
329 if( VLC_SUCCESS != Direct3DVoutOpen( p_vout ) )
331 msg_Err( p_vout, "cannot initialize Direct3D" );
335 /* Initialize the output structure.
336 * Since Direct3D can do rescaling for us, stick to the default
337 * coordinates and aspect. */
338 p_vout->output.i_width = p_vout->render.i_width;
339 p_vout->output.i_height = p_vout->render.i_height;
340 p_vout->output.i_aspect = p_vout->render.i_aspect;
341 p_vout->fmt_out = p_vout->fmt_in;
342 UpdateRects( p_vout, true );
344 /* create picture pool */
345 p_vout->output.i_chroma = 0;
346 i_ret = Direct3DVoutCreatePictures(p_vout, 1);
347 if( VLC_SUCCESS != i_ret )
349 msg_Err(p_vout, "Direct3D picture pool initialization failed !");
354 i_ret = Direct3DVoutCreateScene(p_vout);
355 if( VLC_SUCCESS != i_ret )
357 msg_Err(p_vout, "Direct3D scene initialization failed !");
358 Direct3DVoutReleasePictures(p_vout);
362 /* Change the window title bar text */
363 PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
365 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
369 /*****************************************************************************
370 * End: terminate Sys video thread output method
371 *****************************************************************************
372 * Terminate an output method created by Create.
373 * It is called at the end of the thread.
374 *****************************************************************************/
375 static void End( vout_thread_t *p_vout )
377 Direct3DVoutReleaseScene(p_vout);
378 Direct3DVoutReleasePictures(p_vout);
379 Direct3DVoutClose( p_vout );
382 /*****************************************************************************
383 * Manage: handle Sys events
384 *****************************************************************************
385 * This function should be called regularly by the video output thread.
386 * It returns a non null value if an error occurred.
387 *****************************************************************************/
388 static int Manage( vout_thread_t *p_vout )
390 /* If we do not control our window, we check for geometry changes
391 * ourselves because the parent might not send us its events. */
392 vlc_mutex_lock( &p_vout->p_sys->lock );
393 if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
398 vlc_mutex_unlock( &p_vout->p_sys->lock );
400 GetClientRect( p_vout->p_sys->hparent, &rect_parent );
401 point.x = point.y = 0;
402 ClientToScreen( p_vout->p_sys->hparent, &point );
403 OffsetRect( &rect_parent, point.x, point.y );
405 if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
407 p_vout->p_sys->rect_parent = rect_parent;
409 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
410 rect_parent.right - rect_parent.left,
411 rect_parent.bottom - rect_parent.top,
417 vlc_mutex_unlock( &p_vout->p_sys->lock );
423 if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
425 #if 0 /* need that when bicubic filter is available */
429 GetClientRect(p_vout->p_sys->hvideownd, &rect);
430 width = rect.right-rect.left;
431 height = rect.bottom-rect.top;
433 if( (width != p_vout->p_sys->d3dpp.BackBufferWidth)
434 || (height != p_vout->p_sys->d3dpp.BackBufferHeight) )
436 msg_Dbg(p_vout, "resizing device back buffers to (%lux%lu)", width, height);
437 // need to reset D3D device to resize back buffer
438 if( VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, width, height) )
442 p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
445 /* Check for cropping / aspect changes */
446 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
447 p_vout->i_changes & VOUT_ASPECT_CHANGE )
449 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
450 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
452 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
453 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
454 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
455 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
456 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
457 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
458 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
459 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
460 UpdateRects( p_vout, true );
463 /* We used to call the Win32 PeekMessage function here to read the window
464 * messages. But since window can stay blocked into this function for a
465 * long time (for example when you move your window on the screen), I
466 * decided to isolate PeekMessage in another thread. */
471 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
472 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
474 Win32ToggleFullscreen( p_vout );
476 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
477 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
483 if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
484 (mdate() - p_vout->p_sys->i_lastmoved) >
485 p_vout->p_sys->i_mouse_hide_timeout )
490 /* Hide the cursor only if it is inside our window */
491 GetCursorPos( &point );
492 hwnd = WindowFromPoint(point);
493 if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
495 PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
499 p_vout->p_sys->i_lastmoved = mdate();
504 * "Always on top" status change
506 if( p_vout->p_sys->b_on_top_change )
509 HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
511 var_Get( p_vout, "video-on-top", &val );
513 /* Set the window on top if necessary */
514 if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
517 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
518 MF_BYCOMMAND | MFS_CHECKED );
519 SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
520 SWP_NOSIZE | SWP_NOMOVE );
523 /* The window shouldn't be on top */
524 if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
527 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
528 MF_BYCOMMAND | MFS_UNCHECKED );
529 SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
530 SWP_NOSIZE | SWP_NOMOVE );
533 p_vout->p_sys->b_on_top_change = false;
536 /* Check if the event thread is still running */
537 if( !vlc_object_alive (p_vout->p_sys->p_event) )
539 return VLC_EGENERIC; /* exit */
545 /*****************************************************************************
546 * Display: displays previously rendered output
547 *****************************************************************************
548 * This function sends the currently rendered image to the display, wait until
549 * it is displayed and switch the two rendering buffers, preparing next frame.
550 *****************************************************************************/
551 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
553 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
554 // Present the back buffer contents to the display
555 // stretching and filtering happens here
556 HRESULT hr = IDirect3DDevice9_Present(p_d3ddev,
557 &(p_vout->p_sys->rect_src_clipped),
560 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
564 ** this function is only used once when the first picture is received
565 ** this function will show the video window once a picture is ready
568 static void FirstDisplay( vout_thread_t *p_vout, picture_t *p_pic )
570 /* get initial picture presented through D3D */
571 Display(p_vout, p_pic);
574 ** Video window is initially hidden, show it now since we got a
577 SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
585 /* use and restores proper display function for further pictures */
586 p_vout->pf_display = Display;
589 /*****************************************************************************
590 * DirectD3DVoutCreate: Initialize and instance of Direct3D9
591 *****************************************************************************
592 * This function initialize Direct3D and analyze available resources from
594 *****************************************************************************/
595 static int Direct3DVoutCreate( vout_thread_t *p_vout )
598 LPDIRECT3D9 p_d3dobj;
601 LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
603 p_vout->p_sys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
604 if( NULL == p_vout->p_sys->hd3d9_dll )
606 msg_Warn( p_vout, "cannot load d3d9.dll, aborting" );
611 (void *)GetProcAddress( p_vout->p_sys->hd3d9_dll,
612 TEXT("Direct3DCreate9") );
613 if( OurDirect3DCreate9 == NULL )
615 msg_Err( p_vout, "Cannot locate reference to Direct3DCreate9 ABI in DLL" );
619 /* Create the D3D object. */
620 p_d3dobj = OurDirect3DCreate9( D3D_SDK_VERSION );
621 if( NULL == p_d3dobj )
623 msg_Err( p_vout, "Could not create Direct3D9 instance.");
626 p_vout->p_sys->p_d3dobj = p_d3dobj;
629 ** Get device capabilities
631 ZeroMemory(&d3dCaps, sizeof(d3dCaps));
632 hr = IDirect3D9_GetDeviceCaps(p_d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps);
635 msg_Err( p_vout, "Could not read adapter capabilities. (hr=0x%lX)", hr);
638 /* TODO: need to test device capabilities and select the right render function */
643 /*****************************************************************************
644 * DirectD3DVoutRelease: release an instance of Direct3D9
645 *****************************************************************************/
647 static void Direct3DVoutRelease( vout_thread_t *p_vout )
649 if( p_vout->p_sys->p_d3dobj )
651 IDirect3D9_Release(p_vout->p_sys->p_d3dobj);
652 p_vout->p_sys->p_d3dobj = NULL;
654 if( NULL != p_vout->p_sys->hd3d9_dll )
656 FreeLibrary(p_vout->p_sys->hd3d9_dll);
657 p_vout->p_sys->hd3d9_dll = NULL;
661 static int Direct3DFillPresentationParameters(vout_thread_t *p_vout, D3DPRESENT_PARAMETERS *d3dpp)
663 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
664 D3DDISPLAYMODE d3ddm;
668 ** Get the current desktop display mode, so we can set up a back
669 ** buffer of the same format
671 hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
674 msg_Err( p_vout, "Could not read adapter display mode. (hr=0x%lX)", hr);
678 /* keep a copy of current desktop format */
679 p_vout->p_sys->bbFormat = d3ddm.Format;
681 /* Set up the structure used to create the D3DDevice. */
682 ZeroMemory( d3dpp, sizeof(D3DPRESENT_PARAMETERS) );
683 d3dpp->Flags = D3DPRESENTFLAG_VIDEO;
684 d3dpp->Windowed = TRUE;
685 d3dpp->hDeviceWindow = p_vout->p_sys->hvideownd;
686 d3dpp->BackBufferWidth = p_vout->output.i_width;
687 d3dpp->BackBufferHeight = p_vout->output.i_height;
688 d3dpp->SwapEffect = D3DSWAPEFFECT_COPY;
689 d3dpp->MultiSampleType = D3DMULTISAMPLE_NONE;
690 d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
691 d3dpp->BackBufferFormat = d3ddm.Format;
692 d3dpp->BackBufferCount = 1;
693 d3dpp->EnableAutoDepthStencil = FALSE;
698 /*****************************************************************************
699 * DirectD3DVoutOpen: Takes care of all the Direct3D9 initialisations
700 *****************************************************************************
701 * This function creates Direct3D device
702 * this must be called from the vout thread for performance reason, as
703 * all Direct3D Device APIs are used in a non multithread safe environment
704 *****************************************************************************/
705 static int Direct3DVoutOpen( vout_thread_t *p_vout )
707 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
708 LPDIRECT3DDEVICE9 p_d3ddev;
709 D3DPRESENT_PARAMETERS d3dpp;
712 if( VLC_SUCCESS != Direct3DFillPresentationParameters(p_vout, &d3dpp) )
715 // Create the D3DDevice
716 hr = IDirect3D9_CreateDevice(p_d3dobj, D3DADAPTER_DEFAULT,
717 D3DDEVTYPE_HAL, p_vout->p_sys->hvideownd,
718 D3DCREATE_SOFTWARE_VERTEXPROCESSING|
719 D3DCREATE_MULTITHREADED,
723 msg_Err(p_vout, "Could not create the D3D device! (hr=0x%lX)", hr);
726 p_vout->p_sys->p_d3ddev = p_d3ddev;
728 msg_Dbg( p_vout, "Direct3D device adapter successfully initialized" );
732 /*****************************************************************************
733 * DirectD3DClose: release the Direct3D9 device
734 *****************************************************************************/
735 static void Direct3DVoutClose( vout_thread_t *p_vout )
737 if( p_vout->p_sys->p_d3ddev )
739 IDirect3DDevice9_Release(p_vout->p_sys->p_d3ddev);
740 p_vout->p_sys->p_d3ddev = NULL;
743 p_vout->p_sys->hmonitor = NULL;
746 /*****************************************************************************
747 * DirectD3DClose: reset the Direct3D9 device
748 *****************************************************************************
749 * All resources must be deallocated before the reset occur, they will be
750 * realllocated once the reset has been performed successfully
751 *****************************************************************************/
752 static int Direct3DVoutResetDevice( vout_thread_t *p_vout )
754 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
755 D3DPRESENT_PARAMETERS d3dpp;
758 if( VLC_SUCCESS != Direct3DFillPresentationParameters(p_vout, &d3dpp) )
761 // release all D3D objects
762 Direct3DVoutReleaseScene( p_vout );
763 Direct3DVoutReleasePictures( p_vout );
765 hr = IDirect3DDevice9_Reset(p_d3ddev, &d3dpp);
769 if( (VLC_SUCCESS != Direct3DVoutCreatePictures(p_vout, 1))
770 || (VLC_SUCCESS != Direct3DVoutCreateScene(p_vout)) )
772 msg_Dbg(p_vout, "%s failed !", __FUNCTION__);
777 msg_Err(p_vout, "%s failed ! (hr=%08lX)", __FUNCTION__, hr);
783 static D3DFORMAT Direct3DVoutSelectFormat( vout_thread_t *p_vout, D3DFORMAT target,
784 const D3DFORMAT *formats, size_t count)
786 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
789 for( c=0; c<count; ++c )
792 D3DFORMAT format = formats[c];
793 /* test whether device can create a surface of that format */
794 hr = IDirect3D9_CheckDeviceFormat(p_d3dobj, D3DADAPTER_DEFAULT,
795 D3DDEVTYPE_HAL, target, 0, D3DRTYPE_SURFACE, format);
798 /* test whether device can perform color-conversion
799 ** from that format to target format
801 hr = IDirect3D9_CheckDeviceFormatConversion(p_d3dobj,
802 D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
807 // found a compatible format
811 msg_Dbg( p_vout, "selected surface pixel format is UYVY");
814 msg_Dbg( p_vout, "selected surface pixel format is YUY2");
816 case D3DFMT_X8R8G8B8:
817 msg_Dbg( p_vout, "selected surface pixel format is X8R8G8B8");
819 case D3DFMT_A8R8G8B8:
820 msg_Dbg( p_vout, "selected surface pixel format is A8R8G8B8");
823 msg_Dbg( p_vout, "selected surface pixel format is R8G8B8");
826 msg_Dbg( p_vout, "selected surface pixel format is R5G6B5");
828 case D3DFMT_X1R5G5B5:
829 msg_Dbg( p_vout, "selected surface pixel format is X1R5G5B5");
832 msg_Dbg( p_vout, "selected surface pixel format is 0x%0X", format);
837 else if( D3DERR_NOTAVAILABLE != hr )
839 msg_Err( p_vout, "Could not query adapter supported formats. (hr=0x%lX)", hr);
843 return D3DFMT_UNKNOWN;
846 static D3DFORMAT Direct3DVoutFindFormat(vout_thread_t *p_vout, int i_chroma, D3DFORMAT target)
848 //if( p_vout->p_sys->b_hw_yuv && ! _got_vista_or_above )
849 if( p_vout->p_sys->b_hw_yuv )
851 /* it sounds like vista does not support YUV surfaces at all */
854 case VLC_FOURCC('U','Y','V','Y'):
855 case VLC_FOURCC('U','Y','N','V'):
856 case VLC_FOURCC('Y','4','2','2'):
858 static const D3DFORMAT formats[] =
859 { D3DFMT_UYVY, D3DFMT_YUY2, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
860 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
862 case VLC_FOURCC('I','4','2','0'):
863 case VLC_FOURCC('I','4','2','2'):
864 case VLC_FOURCC('Y','V','1','2'):
866 /* typically 3D textures don't support planar format
867 ** fallback to packed version and use CPU for the conversion
869 static const D3DFORMAT formats[] =
870 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
871 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
873 case VLC_FOURCC('Y','U','Y','2'):
874 case VLC_FOURCC('Y','U','N','V'):
876 static const D3DFORMAT formats[] =
877 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
878 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
885 case VLC_FOURCC('R', 'V', '1', '5'):
887 static const D3DFORMAT formats[] =
889 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
891 case VLC_FOURCC('R', 'V', '1', '6'):
893 static const D3DFORMAT formats[] =
895 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
897 case VLC_FOURCC('R', 'V', '2', '4'):
899 static const D3DFORMAT formats[] =
900 { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
901 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
903 case VLC_FOURCC('R', 'V', '3', '2'):
905 static const D3DFORMAT formats[] =
906 { D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8 };
907 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
911 /* use display default format */
912 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
913 D3DDISPLAYMODE d3ddm;
915 HRESULT hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
919 ** some professional cards could use some advanced pixel format as default,
920 ** make sure we stick with chromas that we can handle internally
922 switch( d3ddm.Format )
925 case D3DFMT_X8R8G8B8:
926 case D3DFMT_A8R8G8B8:
928 case D3DFMT_X1R5G5B5:
929 msg_Dbg( p_vout, "defaulting to adapter pixel format");
930 return Direct3DVoutSelectFormat(p_vout, target, &d3ddm.Format, 1);
933 /* if we fall here, that probably means that we need to render some YUV format */
934 static const D3DFORMAT formats[] =
935 { D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
936 msg_Dbg( p_vout, "defaulting to built-in pixel format");
937 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
943 return D3DFMT_UNKNOWN;
946 static int Direct3DVoutSetOutputFormat(vout_thread_t *p_vout, D3DFORMAT format)
951 p_vout->output.i_chroma = VLC_FOURCC('Y', 'U', 'Y', '2');
954 p_vout->output.i_chroma = VLC_FOURCC('U', 'Y', 'V', 'Y');
957 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '2', '4');
958 p_vout->output.i_rmask = 0xff0000;
959 p_vout->output.i_gmask = 0x00ff00;
960 p_vout->output.i_bmask = 0x0000ff;
962 case D3DFMT_X8R8G8B8:
963 case D3DFMT_A8R8G8B8:
964 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '3', '2');
965 p_vout->output.i_rmask = 0x00ff0000;
966 p_vout->output.i_gmask = 0x0000ff00;
967 p_vout->output.i_bmask = 0x000000ff;
970 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '6');
971 p_vout->output.i_rmask = (0x1fL)<<11;
972 p_vout->output.i_gmask = (0x3fL)<<5;
973 p_vout->output.i_bmask = (0x1fL)<<0;
975 case D3DFMT_X1R5G5B5:
976 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '5');
977 p_vout->output.i_rmask = (0x1fL)<<10;
978 p_vout->output.i_gmask = (0x1fL)<<5;
979 p_vout->output.i_bmask = (0x1fL)<<0;
987 /*****************************************************************************
988 * Direct3DVoutCreatePictures: allocate a vector of identical pictures
989 *****************************************************************************
990 * Each picture has an associated offscreen surface in video memory
991 * depending on hardware capabilities the picture chroma will be as close
992 * as possible to the orginal render chroma to reduce CPU conversion overhead
993 * and delegate this work to video card GPU
994 *****************************************************************************/
995 static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics )
997 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1001 // if vout is already running, use current chroma, otherwise choose from upstream
1002 int i_chroma = p_vout->output.i_chroma ? : p_vout->render.i_chroma;
1004 I_OUTPUTPICTURES = 0;
1007 ** find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
1008 ** the requested chroma which is usable by the hardware in an offscreen surface, as they
1009 ** typically support more formats than textures
1011 format = Direct3DVoutFindFormat(p_vout, i_chroma, p_vout->p_sys->bbFormat);
1012 if( VLC_SUCCESS != Direct3DVoutSetOutputFormat(p_vout, format) )
1014 msg_Err(p_vout, "surface pixel format is not supported.");
1015 return VLC_EGENERIC;
1018 for( c=0; c<i_num_pics; )
1021 LPDIRECT3DSURFACE9 p_d3dsurf;
1022 picture_t *p_pic = p_vout->p_picture+c;
1024 hr = IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3ddev,
1025 p_vout->render.i_width,
1026 p_vout->render.i_height,
1033 msg_Err(p_vout, "Failed to create picture surface. (hr=0x%lx)", hr);
1034 Direct3DVoutReleasePictures(p_vout);
1035 return VLC_EGENERIC;
1038 /* fill surface with black color */
1039 IDirect3DDevice9_ColorFill(p_d3ddev, p_d3dsurf, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
1041 /* assign surface to internal structure */
1042 p_pic->p_sys = (void *)p_d3dsurf;
1044 /* Now that we've got our direct-buffer, we can finish filling in the
1045 * picture_t structures */
1046 switch( p_vout->output.i_chroma )
1048 case VLC_FOURCC('R','G','B','2'):
1049 p_pic->p->i_lines = p_vout->output.i_height;
1050 p_pic->p->i_visible_lines = p_vout->output.i_height;
1051 p_pic->p->i_pixel_pitch = 1;
1052 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1053 p_pic->p->i_pixel_pitch;
1054 p_pic->i_planes = 1;
1056 case VLC_FOURCC('R','V','1','5'):
1057 case VLC_FOURCC('R','V','1','6'):
1058 p_pic->p->i_lines = p_vout->output.i_height;
1059 p_pic->p->i_visible_lines = p_vout->output.i_height;
1060 p_pic->p->i_pixel_pitch = 2;
1061 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1062 p_pic->p->i_pixel_pitch;
1063 p_pic->i_planes = 1;
1065 case VLC_FOURCC('R','V','2','4'):
1066 p_pic->p->i_lines = p_vout->output.i_height;
1067 p_pic->p->i_visible_lines = p_vout->output.i_height;
1068 p_pic->p->i_pixel_pitch = 3;
1069 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1070 p_pic->p->i_pixel_pitch;
1071 p_pic->i_planes = 1;
1073 case VLC_FOURCC('R','V','3','2'):
1074 p_pic->p->i_lines = p_vout->output.i_height;
1075 p_pic->p->i_visible_lines = p_vout->output.i_height;
1076 p_pic->p->i_pixel_pitch = 4;
1077 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1078 p_pic->p->i_pixel_pitch;
1079 p_pic->i_planes = 1;
1081 case VLC_FOURCC('U','Y','V','Y'):
1082 case VLC_FOURCC('Y','U','Y','2'):
1083 p_pic->p->i_lines = p_vout->output.i_height;
1084 p_pic->p->i_visible_lines = p_vout->output.i_height;
1085 p_pic->p->i_pixel_pitch = 2;
1086 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1087 p_pic->p->i_pixel_pitch;
1088 p_pic->i_planes = 1;
1091 Direct3DVoutReleasePictures(p_vout);
1092 return VLC_EGENERIC;
1094 p_pic->i_status = DESTROYED_PICTURE;
1095 p_pic->i_type = DIRECT_PICTURE;
1096 p_pic->b_slow = true;
1097 p_pic->pf_lock = Direct3DVoutLockSurface;
1098 p_pic->pf_unlock = Direct3DVoutUnlockSurface;
1099 PP_OUTPUTPICTURE[c] = p_pic;
1101 I_OUTPUTPICTURES = ++c;
1104 msg_Dbg( p_vout, "%u Direct3D pictures created successfully", c );
1109 /*****************************************************************************
1110 * Direct3DVoutReleasePictures: destroy a picture vector
1111 *****************************************************************************
1112 * release all video resources used for pictures
1113 *****************************************************************************/
1114 static void Direct3DVoutReleasePictures( vout_thread_t *p_vout)
1116 size_t i_num_pics = I_OUTPUTPICTURES;
1118 for( c=0; c<i_num_pics; ++c )
1120 picture_t *p_pic = p_vout->p_picture+c;
1123 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1125 p_pic->p_sys = NULL;
1129 IDirect3DSurface9_Release(p_d3dsurf);
1133 msg_Dbg( p_vout, "%u Direct3D pictures released.", c);
1135 I_OUTPUTPICTURES = 0;
1138 /*****************************************************************************
1139 * Direct3DVoutLockSurface: Lock surface and get picture data pointer
1140 *****************************************************************************
1141 * This function locks a surface and get the surface descriptor which amongst
1142 * other things has the pointer to the picture data.
1143 *****************************************************************************/
1144 static int Direct3DVoutLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1147 D3DLOCKED_RECT d3drect;
1148 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1150 if( NULL == p_d3dsurf )
1151 return VLC_EGENERIC;
1153 /* Lock the surface to get a valid pointer to the picture buffer */
1154 hr = IDirect3DSurface9_LockRect(p_d3dsurf, &d3drect, NULL, 0);
1157 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1158 return VLC_EGENERIC;
1161 /* fill in buffer info in first plane */
1162 p_pic->p->p_pixels = d3drect.pBits;
1163 p_pic->p->i_pitch = d3drect.Pitch;
1168 /*****************************************************************************
1169 * Direct3DVoutUnlockSurface: Unlock a surface locked by Direct3DLockSurface().
1170 *****************************************************************************/
1171 static int Direct3DVoutUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1174 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1176 if( NULL == p_d3dsurf )
1177 return VLC_EGENERIC;
1179 /* Unlock the Surface */
1180 hr = IDirect3DSurface9_UnlockRect(p_d3dsurf);
1183 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1184 return VLC_EGENERIC;
1189 /*****************************************************************************
1190 * Direct3DVoutCreateScene: allocate and initialize a 3D scene
1191 *****************************************************************************
1192 * for advanced blending/filtering a texture needs be used in a 3D scene.
1193 *****************************************************************************/
1195 static int Direct3DVoutCreateScene( vout_thread_t *p_vout )
1197 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1198 LPDIRECT3DTEXTURE9 p_d3dtex;
1199 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
1204 ** Create a texture for use when rendering a scene
1205 ** for performance reason, texture format is identical to backbuffer
1206 ** which would usually be a RGB format
1208 hr = IDirect3DDevice9_CreateTexture(p_d3ddev,
1209 p_vout->render.i_width,
1210 p_vout->render.i_height,
1212 D3DUSAGE_RENDERTARGET,
1213 p_vout->p_sys->bbFormat,
1219 msg_Err(p_vout, "Failed to create texture. (hr=0x%lx)", hr);
1220 return VLC_EGENERIC;
1224 ** Create a vertex buffer for use when rendering scene
1226 hr = IDirect3DDevice9_CreateVertexBuffer(p_d3ddev,
1227 sizeof(CUSTOMVERTEX)*4,
1228 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
1229 D3DFVF_CUSTOMVERTEX,
1235 msg_Err(p_vout, "Failed to create vertex buffer. (hr=0x%lx)", hr);
1236 IDirect3DTexture9_Release(p_d3dtex);
1237 return VLC_EGENERIC;
1240 p_vout->p_sys->p_d3dtex = p_d3dtex;
1241 p_vout->p_sys->p_d3dvtc = p_d3dvtc;
1243 // Texture coordinates outside the range [0.0, 1.0] are set
1244 // to the texture color at 0.0 or 1.0, respectively.
1245 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1246 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1248 // Set linear filtering quality
1249 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
1250 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
1252 // set maximum ambient light
1253 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
1256 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_CULLMODE, D3DCULL_NONE);
1258 // Turn off the zbuffer
1259 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ZENABLE, D3DZB_FALSE);
1262 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_LIGHTING, FALSE);
1265 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DITHERENABLE, TRUE);
1268 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_STENCILENABLE, FALSE);
1271 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
1272 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
1273 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
1274 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHATESTENABLE,TRUE);
1275 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAREF, 0x10);
1276 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER);
1278 // Set texture states
1279 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE);
1280 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
1281 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
1283 // turn off alpha operation
1284 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
1286 msg_Dbg( p_vout, "Direct3D scene created successfully");
1291 /*****************************************************************************
1292 * Direct3DVoutReleaseScene
1293 *****************************************************************************/
1294 static void Direct3DVoutReleaseScene( vout_thread_t *p_vout )
1296 LPDIRECT3DTEXTURE9 p_d3dtex = p_vout->p_sys->p_d3dtex;
1297 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1301 IDirect3DVertexBuffer9_Release(p_d3dvtc);
1302 p_vout->p_sys->p_d3dvtc = NULL;
1307 IDirect3DTexture9_Release(p_d3dtex);
1308 p_vout->p_sys->p_d3dtex = NULL;
1310 msg_Dbg( p_vout, "Direct3D scene released successfully");
1313 /*****************************************************************************
1314 * Render: copy picture surface into a texture and render into a scene
1315 *****************************************************************************
1316 * This function is intented for higher end 3D cards, with pixel shader support
1317 * and at least 64 MB of video RAM.
1318 *****************************************************************************/
1319 static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic )
1321 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1322 LPDIRECT3DTEXTURE9 p_d3dtex;
1323 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
1324 LPDIRECT3DSURFACE9 p_d3dsrc, p_d3ddest;
1325 CUSTOMVERTEX *p_vertices;
1327 float f_width, f_height;
1329 // check if device is still available
1330 hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
1333 if( (D3DERR_DEVICENOTRESET != hr)
1334 || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout)) )
1336 // device is not usable at present (lost device, out of video mem ?)
1340 p_d3dtex = p_vout->p_sys->p_d3dtex;
1341 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1343 /* Clear the backbuffer and the zbuffer */
1344 hr = IDirect3DDevice9_Clear( p_d3ddev, 0, NULL, D3DCLEAR_TARGET,
1345 D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0 );
1348 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1352 /* retrieve picture surface */
1353 p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1354 if( NULL == p_d3dsrc )
1356 msg_Dbg( p_vout, "no surface to render ?");
1360 /* retrieve texture top-level surface */
1361 hr = IDirect3DTexture9_GetSurfaceLevel(p_d3dtex, 0, &p_d3ddest);
1364 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1368 /* Copy picture surface into texture surface, color space conversion happens here */
1369 hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, NULL, p_d3ddest, NULL, D3DTEXF_NONE);
1370 IDirect3DSurface9_Release(p_d3ddest);
1373 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1377 /* Update the vertex buffer */
1378 hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (VOID **)(&p_vertices), D3DLOCK_DISCARD);
1381 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1385 /* Setup vertices */
1386 f_width = (float)(p_vout->output.i_width) + 1;
1387 f_height = (float)(p_vout->output.i_height) + 1;
1389 p_vertices[0].x = 0.0f; // left
1390 p_vertices[0].y = 0.0f; // top
1391 p_vertices[0].z = 0.0f;
1392 p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1393 p_vertices[0].rhw = 1.0f;
1394 p_vertices[0].tu = 0.0f;
1395 p_vertices[0].tv = 0.0f;
1397 p_vertices[1].x = f_width; // right
1398 p_vertices[1].y = 0.0f; // top
1399 p_vertices[1].z = 0.0f;
1400 p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1401 p_vertices[1].rhw = 1.0f;
1402 p_vertices[1].tu = 1.0f;
1403 p_vertices[1].tv = 0.0f;
1405 p_vertices[2].x = f_width; // right
1406 p_vertices[2].y = f_height; // bottom
1407 p_vertices[2].z = 0.0f;
1408 p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1409 p_vertices[2].rhw = 1.0f;
1410 p_vertices[2].tu = 1.0f;
1411 p_vertices[2].tv = 1.0f;
1413 p_vertices[3].x = 0.0f; // left
1414 p_vertices[3].y = f_height; // bottom
1415 p_vertices[3].z = 0.0f;
1416 p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1417 p_vertices[3].rhw = 1.0f;
1418 p_vertices[3].tu = 0.0f;
1419 p_vertices[3].tv = 1.0f;
1421 hr= IDirect3DVertexBuffer9_Unlock(p_d3dvtc);
1424 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1429 hr = IDirect3DDevice9_BeginScene(p_d3ddev);
1432 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1436 // Setup our texture. Using textures introduces the texture stage states,
1437 // which govern how textures get blended together (in the case of multiple
1438 // textures) and lighting information. In this case, we are modulating
1439 // (blending) our texture with the diffuse color of the vertices.
1440 hr = IDirect3DDevice9_SetTexture(p_d3ddev, 0, (LPDIRECT3DBASETEXTURE9)p_d3dtex);
1443 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1444 IDirect3DDevice9_EndScene(p_d3ddev);
1448 // Render the vertex buffer contents
1449 hr = IDirect3DDevice9_SetStreamSource(p_d3ddev, 0, p_d3dvtc, 0, sizeof(CUSTOMVERTEX));
1452 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1453 IDirect3DDevice9_EndScene(p_d3ddev);
1457 // we use FVF instead of vertex shader
1458 hr = IDirect3DDevice9_SetVertexShader(p_d3ddev, NULL);
1461 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1462 IDirect3DDevice9_EndScene(p_d3ddev);
1466 hr = IDirect3DDevice9_SetFVF(p_d3ddev, D3DFVF_CUSTOMVERTEX);
1469 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1470 IDirect3DDevice9_EndScene(p_d3ddev);
1475 hr = IDirect3DDevice9_DrawPrimitive(p_d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
1478 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1479 IDirect3DDevice9_EndScene(p_d3ddev);
1484 hr = IDirect3DDevice9_EndScene(p_d3ddev);
1487 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);