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 overlay if supported, using overlay 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. This fallback method also enables us to
34 * display video in window mode.
36 *****************************************************************************/
37 #include <errno.h> /* ENOMEM */
38 #include <stdlib.h> /* free() */
39 #include <string.h> /* strerror() */
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 * );
61 static int Direct3DVoutCreate ( vout_thread_t * );
62 static void Direct3DVoutRelease ( vout_thread_t * );
64 static int Direct3DVoutOpen ( vout_thread_t * );
65 static void Direct3DVoutClose ( vout_thread_t * );
67 static int Direct3DVoutResetDevice( vout_thread_t *, UINT , UINT );
69 static int Direct3DVoutCreatePictures ( vout_thread_t *, size_t );
70 static void Direct3DVoutReleasePictures ( vout_thread_t * );
72 static int Direct3DVoutLockSurface ( vout_thread_t *, picture_t * );
73 static int Direct3DVoutUnlockSurface( vout_thread_t *, picture_t * );
75 static void Direct3DVoutRenderDefault ( vout_thread_t *, picture_t * );
77 static int Direct3DVoutCreateScene ( vout_thread_t * );
78 static void Direct3DVoutReleaseScene ( vout_thread_t * );
79 static void Direct3DVoutRenderScene ( vout_thread_t *, picture_t * );
81 /*****************************************************************************
83 *****************************************************************************/
85 set_shortname( "Direct3D" );
86 set_category( CAT_VIDEO );
87 set_subcategory( SUBCAT_VIDEO_VOUT );
88 set_description( _("DirectX 3D video output") );
89 set_capability( "video output", 150 );
90 add_shortcut( "direct3d" );
91 set_callbacks( OpenVideo, CloseVideo );
93 /* FIXME: Hack to avoid unregistering our window class */
94 linked_with_a_crap_library_which_uses_atexit( );
98 /* check if we registered a window class because we need to
101 if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
102 UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
105 /*****************************************************************************
107 *****************************************************************************
108 *****************************************************************************/
111 FLOAT x,y,z; // vertex untransformed position
112 FLOAT rhw; // eye distance
113 D3DCOLOR diffuse; // diffuse color
114 FLOAT tu, tv; // texture relative coordinates
117 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
119 /*****************************************************************************
120 * OpenVideo: allocate DirectX video thread output method
121 *****************************************************************************
122 * This function allocates and initialize the DirectX vout method.
123 *****************************************************************************/
124 static int OpenVideo( vlc_object_t *p_this )
126 vout_thread_t * p_vout = (vout_thread_t *)p_this;
129 /* Allocate structure */
130 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
131 if( p_vout->p_sys == NULL )
133 msg_Err( p_vout, "out of memory" );
136 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
138 if( VLC_SUCCESS != Direct3DVoutCreate( p_vout ) )
140 msg_Err( p_vout, "Direct3D could not be initialized !");
144 /* Initialisations */
145 p_vout->pf_init = Init;
146 p_vout->pf_end = End;
147 p_vout->pf_manage = Manage;
148 p_vout->pf_render = Direct3DVoutRenderScene;
149 p_vout->pf_display = Display;
151 p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
152 p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
153 p_vout->p_sys->i_changes = 0;
154 p_vout->p_sys->b_wallpaper = 0;
155 vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
156 SetRectEmpty( &p_vout->p_sys->rect_display );
157 SetRectEmpty( &p_vout->p_sys->rect_parent );
159 p_vout->p_sys->b_cursor_hidden = 0;
160 p_vout->p_sys->i_lastmoved = mdate();
162 /* Set main window's size */
163 p_vout->p_sys->i_window_width = p_vout->i_window_width;
164 p_vout->p_sys->i_window_height = p_vout->i_window_height;
166 /* Create the DirectXEventThread, this thread is created by us to isolate
167 * the Win32 PeekMessage function calls. We want to do this because
168 * Windows can stay blocked inside this call for a long time, and when
169 * this happens it thus blocks vlc's video_output thread.
170 * DirectXEventThread will take care of the creation of the video
171 * window (because PeekMessage has to be called from the same thread which
172 * created the window). */
173 msg_Dbg( p_vout, "creating DirectXEventThread" );
174 p_vout->p_sys->p_event =
175 vlc_object_create( p_vout, sizeof(event_thread_t) );
176 p_vout->p_sys->p_event->p_vout = p_vout;
177 if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
178 E_(DirectXEventThread), 0, 1 ) )
180 msg_Err( p_vout, "cannot create DirectXEventThread" );
181 vlc_object_destroy( p_vout->p_sys->p_event );
182 p_vout->p_sys->p_event = NULL;
186 if( p_vout->p_sys->p_event->b_error )
188 msg_Err( p_vout, "DirectXEventThread failed" );
192 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
194 msg_Dbg( p_vout, "DirectXEventThread running" );
196 /* Variable to indicate if the window should be on top of others */
197 /* Trigger a callback right now */
198 var_Get( p_vout, "video-on-top", &val );
199 var_Set( p_vout, "video-on-top", val );
201 /* disable screensaver by temporarily changing system settings */
202 p_vout->p_sys->i_spi_lowpowertimeout = 0;
203 p_vout->p_sys->i_spi_powerofftimeout = 0;
204 p_vout->p_sys->i_spi_screensavetimeout = 0;
205 var_Get( p_vout, "disable-screensaver", &val);
207 msg_Dbg(p_vout, "disabling screen saver");
208 SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
209 0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
210 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
211 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
213 SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
214 &(p_vout->p_sys->i_spi_powerofftimeout), 0);
215 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
216 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
218 SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
219 &(p_vout->p_sys->i_spi_screensavetimeout), 0);
220 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
221 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
227 CloseVideo( VLC_OBJECT(p_vout) );
231 /*****************************************************************************
232 * CloseVideo: destroy Sys video thread output method
233 *****************************************************************************
234 * Terminate an output method created by Create
235 *****************************************************************************/
236 static void CloseVideo( vlc_object_t *p_this )
238 vout_thread_t * p_vout = (vout_thread_t *)p_this;
240 Direct3DVoutRelease( p_vout );
242 if( p_vout->p_sys->p_event )
244 vlc_object_detach( p_vout->p_sys->p_event );
246 /* Kill DirectXEventThread */
247 p_vout->p_sys->p_event->b_die = VLC_TRUE;
249 /* we need to be sure DirectXEventThread won't stay stuck in
250 * GetMessage, so we send a fake message */
251 if( p_vout->p_sys->hwnd )
253 PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
256 vlc_thread_join( p_vout->p_sys->p_event );
257 vlc_object_destroy( p_vout->p_sys->p_event );
260 vlc_mutex_destroy( &p_vout->p_sys->lock );
262 /* restore screensaver system settings */
263 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
264 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
265 p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
267 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
268 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
269 p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
271 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
272 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
273 p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
278 free( p_vout->p_sys );
279 p_vout->p_sys = NULL;
283 /*****************************************************************************
284 * Init: initialize Direct3D video thread output method
285 *****************************************************************************/
286 static int Init( vout_thread_t *p_vout )
290 /* Initialise Direct3D */
291 if( VLC_SUCCESS != Direct3DVoutOpen( p_vout ) )
293 msg_Err( p_vout, "cannot initialize Direct3D" );
297 /* Initialize the output structure.
298 * Since Direct3D can do rescaling for us, stick to the default
299 * coordinates and aspect. */
300 p_vout->output.i_width = p_vout->render.i_width;
301 p_vout->output.i_height = p_vout->render.i_height;
302 p_vout->output.i_aspect = p_vout->render.i_aspect;
303 p_vout->fmt_out = p_vout->fmt_in;
304 E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
306 /* create picture pool */
307 i_ret = Direct3DVoutCreatePictures(p_vout, 1);
308 if( VLC_SUCCESS != i_ret )
310 msg_Err(p_vout, "Direct3D picture pool initialization failed !");
315 i_ret = Direct3DVoutCreateScene(p_vout);
316 if( VLC_SUCCESS != i_ret )
318 msg_Err(p_vout, "Direct3D scene initialization failed !");
319 Direct3DVoutReleasePictures(p_vout);
323 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
327 /*****************************************************************************
328 * End: terminate Sys video thread output method
329 *****************************************************************************
330 * Terminate an output method created by Create.
331 * It is called at the end of the thread.
332 *****************************************************************************/
333 static void End( vout_thread_t *p_vout )
335 Direct3DVoutReleaseScene(p_vout);
336 Direct3DVoutReleasePictures(p_vout);
337 Direct3DVoutClose( p_vout );
340 /*****************************************************************************
341 * Manage: handle Sys events
342 *****************************************************************************
343 * This function should be called regularly by the video output thread.
344 * It returns a non null value if an error occurred.
345 *****************************************************************************/
346 static int Manage( vout_thread_t *p_vout )
348 WINDOWPLACEMENT window_placement;
350 /* If we do not control our window, we check for geometry changes
351 * ourselves because the parent might not send us its events. */
352 vlc_mutex_lock( &p_vout->p_sys->lock );
353 if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
358 vlc_mutex_unlock( &p_vout->p_sys->lock );
360 GetClientRect( p_vout->p_sys->hparent, &rect_parent );
361 point.x = point.y = 0;
362 ClientToScreen( p_vout->p_sys->hparent, &point );
363 OffsetRect( &rect_parent, point.x, point.y );
365 if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
367 p_vout->p_sys->rect_parent = rect_parent;
369 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
370 rect_parent.right - rect_parent.left,
371 rect_parent.bottom - rect_parent.top, 0 );
376 vlc_mutex_unlock( &p_vout->p_sys->lock );
382 if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
384 #if 0 /* need that when bicubic filter is available */
388 GetClientRect(p_vout->p_sys->hvideownd, &rect);
389 width = rect.right-rect.left;
390 height = rect.bottom-rect.top;
392 if( (width != p_vout->p_sys->d3dpp.BackBufferWidth)
393 || (height != p_vout->p_sys->d3dpp.BackBufferHeight) )
395 msg_Dbg(p_vout, "resizing device back buffers to (%lux%lu)", width, height);
396 // need to reset D3D device to resize back buffer
397 if( VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, width, height) )
401 p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
404 /* Check for cropping / aspect changes */
405 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
406 p_vout->i_changes & VOUT_ASPECT_CHANGE )
408 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
409 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
411 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
412 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
413 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
414 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
415 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
416 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
417 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
418 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
419 E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
422 /* We used to call the Win32 PeekMessage function here to read the window
423 * messages. But since window can stay blocked into this function for a
424 * long time (for example when you move your window on the screen), I
425 * decided to isolate PeekMessage in another thread. */
430 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
431 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
434 HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ?
435 p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd;
437 p_vout->b_fullscreen = ! p_vout->b_fullscreen;
439 /* We need to switch between Maximized and Normal sized window */
440 window_placement.length = sizeof(WINDOWPLACEMENT);
441 GetWindowPlacement( hwnd, &window_placement );
442 if( p_vout->b_fullscreen )
444 /* Change window style, no borders and no title bar */
445 int i_style = WS_CLIPCHILDREN | WS_VISIBLE;
446 SetWindowLong( hwnd, GWL_STYLE, i_style );
448 if( p_vout->p_sys->hparent )
450 /* Retrieve current window position so fullscreen will happen
451 * on the right screen */
454 ClientToScreen( p_vout->p_sys->hwnd, &point );
455 GetClientRect( p_vout->p_sys->hwnd, &rect );
456 SetWindowPos( hwnd, 0, point.x, point.y,
457 rect.right, rect.bottom,
458 SWP_NOZORDER|SWP_FRAMECHANGED );
459 GetWindowPlacement( hwnd, &window_placement );
462 /* Maximize window */
463 window_placement.showCmd = SW_SHOWMAXIMIZED;
464 SetWindowPlacement( hwnd, &window_placement );
465 SetWindowPos( hwnd, 0, 0, 0, 0, 0,
466 SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
468 if( p_vout->p_sys->hparent )
471 GetClientRect( hwnd, &rect );
472 SetParent( p_vout->p_sys->hwnd, hwnd );
473 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
474 rect.right, rect.bottom,
475 SWP_NOZORDER|SWP_FRAMECHANGED );
478 SetForegroundWindow( hwnd );
482 /* Change window style, no borders and no title bar */
483 SetWindowLong( hwnd, GWL_STYLE, p_vout->p_sys->i_window_style );
486 window_placement.showCmd = SW_SHOWNORMAL;
487 SetWindowPlacement( hwnd, &window_placement );
488 SetWindowPos( hwnd, 0, 0, 0, 0, 0,
489 SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
491 if( p_vout->p_sys->hparent )
494 GetClientRect( p_vout->p_sys->hparent, &rect );
495 SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
496 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
497 rect.right, rect.bottom,
498 SWP_NOZORDER|SWP_FRAMECHANGED );
500 ShowWindow( hwnd, SW_HIDE );
501 SetForegroundWindow( p_vout->p_sys->hparent );
504 /* Make sure the mouse cursor is displayed */
505 PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
508 /* Update the object variable and trigger callback */
509 val.b_bool = p_vout->b_fullscreen;
510 var_Set( p_vout, "fullscreen", val );
512 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
513 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
519 if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
520 (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 )
525 /* Hide the cursor only if it is inside our window */
526 GetCursorPos( &point );
527 hwnd = WindowFromPoint(point);
528 if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
530 PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
534 p_vout->p_sys->i_lastmoved = mdate();
539 * "Always on top" status change
541 if( p_vout->p_sys->b_on_top_change )
544 HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
546 var_Get( p_vout, "video-on-top", &val );
548 /* Set the window on top if necessary */
549 if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
552 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
553 MF_BYCOMMAND | MFS_CHECKED );
554 SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
555 SWP_NOSIZE | SWP_NOMOVE );
558 /* The window shouldn't be on top */
559 if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
562 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
563 MF_BYCOMMAND | MFS_UNCHECKED );
564 SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
565 SWP_NOSIZE | SWP_NOMOVE );
568 p_vout->p_sys->b_on_top_change = VLC_FALSE;
571 /* Check if the event thread is still running */
572 if( p_vout->p_sys->p_event->b_die )
574 return VLC_EGENERIC; /* exit */
580 /*****************************************************************************
581 * Display: displays previously rendered output
582 *****************************************************************************
583 * This function sends the currently rendered image to the display, wait until
584 * it is displayed and switch the two rendering buffers, preparing next frame.
585 *****************************************************************************/
586 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
588 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
589 // Present the backbuffer contents to the display
590 HRESULT hr = IDirect3DDevice9_Present(p_d3ddev, NULL, NULL, NULL, NULL);
592 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
595 /*****************************************************************************
596 * DirectD3DVoutCreate: Initialize and instance of Direct3D9
597 *****************************************************************************
598 * This function initialize Direct3D and analyze available resources from
600 *****************************************************************************/
601 static int Direct3DVoutCreate( vout_thread_t *p_vout )
604 LPDIRECT3D9 p_d3dobj;
607 /* Create the D3D object. */
608 p_d3dobj = Direct3DCreate9( D3D_SDK_VERSION );
609 if( NULL == p_d3dobj )
611 msg_Err( p_vout, "Could not create Direct3D9 instance.");
614 p_vout->p_sys->p_d3dobj = p_d3dobj;
617 ** Get device capabilities
619 ZeroMemory(&d3dCaps, sizeof(d3dCaps));
620 hr = IDirect3D9_GetDeviceCaps(p_d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps);
623 msg_Err( p_vout, "Could not read adapter capabilities. (hr=0x%lX)", hr);
626 /* TODO: need to test device capabilities and select the right render function */
631 /*****************************************************************************
632 * DirectD3DVoutRelease: release an instance of Direct3D9
633 *****************************************************************************/
635 static void Direct3DVoutRelease( vout_thread_t *p_vout )
637 if( p_vout->p_sys->p_d3dobj )
639 IDirect3D9_Release(p_vout->p_sys->p_d3dobj);
640 p_vout->p_sys->p_d3dobj = NULL;
644 /*****************************************************************************
645 * DirectD3DVoutOpen: Takes care of all the Direct3D9 initialisations
646 *****************************************************************************
647 * This function creates Direct3D device
648 * this must be called from the vout thread for performance reason, as
649 * all Direct3D Device APIs are used in a non multithread safe environment
650 *****************************************************************************/
651 static int Direct3DVoutOpen( vout_thread_t *p_vout )
654 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;;
655 D3DDISPLAYMODE d3ddm;
656 LPDIRECT3DDEVICE9 p_d3ddev;
659 ** Get the current desktop display mode, so we can set up a back
660 ** buffer of the same format
662 hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
665 msg_Err( p_vout, "Could not read adapter display mode. (hr=0x%lX)", hr);
669 /* Set up the structure used to create the D3DDevice. */
670 ZeroMemory( &p_vout->p_sys->d3dpp, sizeof(D3DPRESENT_PARAMETERS) );
671 p_vout->p_sys->d3dpp.Windowed = TRUE;
672 p_vout->p_sys->d3dpp.hDeviceWindow = p_vout->p_sys->hvideownd;
673 p_vout->p_sys->d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
674 p_vout->p_sys->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
675 p_vout->p_sys->d3dpp.BackBufferFormat = d3ddm.Format;
676 p_vout->p_sys->d3dpp.BackBufferCount = 1;
677 p_vout->p_sys->d3dpp.EnableAutoDepthStencil = TRUE;
678 p_vout->p_sys->d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
680 // Create the D3DDevice
681 hr = IDirect3D9_CreateDevice(p_d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL,
682 D3DCREATE_SOFTWARE_VERTEXPROCESSING, &(p_vout->p_sys->d3dpp), &p_d3ddev );
685 msg_Err(p_vout, "Could not create the D3D device! (hr=0x%lX)", hr);
688 p_vout->p_sys->p_d3ddev = p_d3ddev;
690 msg_Dbg( p_vout, "Direct3D device adapter successfully initialized" );
694 /*****************************************************************************
695 * DirectD3DClose: release the Direct3D9 device
696 *****************************************************************************/
697 static void Direct3DVoutClose( vout_thread_t *p_vout )
699 if( p_vout->p_sys->p_d3ddev )
701 IDirect3DDevice9_Release(p_vout->p_sys->p_d3ddev);
702 p_vout->p_sys->p_d3ddev = NULL;
705 p_vout->p_sys->hmonitor = NULL;
708 /*****************************************************************************
709 * DirectD3DClose: reset the Direct3D9 device
710 *****************************************************************************
711 * All resources must be deallocated before the reset occur, they will be
712 * realllocated once the reset has been performed successfully
713 *****************************************************************************/
714 static int Direct3DVoutResetDevice( vout_thread_t *p_vout, UINT i_width, UINT i_height )
716 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
717 D3DPRESENT_PARAMETERS d3dpp;
720 memcpy(&d3dpp, &(p_vout->p_sys->d3dpp), sizeof(d3dpp));
722 d3dpp.BackBufferWidth = i_width;
724 d3dpp.BackBufferHeight = i_height;
726 // release all D3D objects
727 Direct3DVoutReleaseScene( p_vout );
728 Direct3DVoutReleasePictures( p_vout );
730 hr = IDirect3DDevice9_Reset(p_d3ddev, &d3dpp);
734 if( (VLC_SUCCESS == Direct3DVoutCreatePictures(p_vout, 1))
735 && (VLC_SUCCESS == Direct3DVoutCreateScene(p_vout)) )
737 p_vout->p_sys->d3dpp.BackBufferWidth = i_width;
738 p_vout->p_sys->d3dpp.BackBufferHeight = i_height;
744 msg_Err(p_vout, "%s failed ! (hr=%08lX)", __FUNCTION__, hr);
750 static D3DFORMAT Direct3DVoutSelectFormat( vout_thread_t *p_vout, D3DFORMAT target,
751 const D3DFORMAT *formats, size_t count)
753 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
756 for( c=0; c<count; ++c )
759 D3DFORMAT format = formats[c];
760 hr = IDirect3D9_CheckDeviceFormatConversion(p_d3dobj,
761 D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
765 // found a compatible format
769 msg_Dbg( p_vout, "selected surface pixel format is UYVY");
772 msg_Dbg( p_vout, "selected surface pixel format is YUY2");
774 case D3DFMT_X8R8G8B8:
775 msg_Dbg( p_vout, "selected surface pixel format is X8R8G8B8");
777 case D3DFMT_A8R8G8B8:
778 msg_Dbg( p_vout, "selected surface pixel format is A8R8G8B8");
781 msg_Dbg( p_vout, "selected surface pixel format is R8G8B8");
784 msg_Dbg( p_vout, "selected surface pixel format is R5G6B5");
786 case D3DFMT_X1R5G5B5:
787 msg_Dbg( p_vout, "selected surface pixel format is X1R5G5B5");
790 msg_Dbg( p_vout, "selected surface pixel format is 0x%0X", format);
795 else if( D3DERR_NOTAVAILABLE != hr )
797 msg_Err( p_vout, "Could not query adapter supported formats. (hr=0x%lX)", hr);
801 return D3DFMT_UNKNOWN;
804 D3DFORMAT Direct3DVoutFindFormat(vout_thread_t *p_vout, int i_chroma, D3DFORMAT target)
808 case VLC_FOURCC('U','Y','V','Y'):
809 case VLC_FOURCC('U','Y','N','V'):
810 case VLC_FOURCC('Y','4','2','2'):
812 static const D3DFORMAT formats[] =
813 { D3DFMT_UYVY, D3DFMT_YUY2, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
814 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
816 case VLC_FOURCC('I','4','2','0'):
817 case VLC_FOURCC('Y','V','1','2'):
819 /* typically 3D textures don't support planar format
820 ** fallback to packed version and use pixel
821 ** shader or CPU for the conversion
823 static const D3DFORMAT formats[] =
824 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
825 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
827 case VLC_FOURCC('Y','U','Y','2'):
828 case VLC_FOURCC('Y','U','N','V'):
830 static const D3DFORMAT formats[] =
831 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
832 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
834 case VLC_FOURCC('R', 'V', '1', '5'):
836 static const D3DFORMAT formats[] =
838 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
840 case VLC_FOURCC('R', 'V', '1', '6'):
842 static const D3DFORMAT formats[] =
844 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
846 case VLC_FOURCC('R', 'V', '2', '4'):
848 static const D3DFORMAT formats[] =
849 { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
850 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
852 case VLC_FOURCC('R', 'V', '3', '2'):
854 static const D3DFORMAT formats[] =
855 { D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8 };
856 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
861 return D3DFMT_UNKNOWN;
864 static int Direct3DVoutSetOutputFormat(vout_thread_t *p_vout, D3DFORMAT format)
869 p_vout->output.i_chroma = VLC_FOURCC('Y', 'U', 'Y', '2');
872 p_vout->output.i_chroma = VLC_FOURCC('U', 'Y', 'V', 'Y');
874 case D3DFMT_X8R8G8B8:
875 case D3DFMT_A8R8G8B8:
877 ** FIXME: some custom masks are not handled properly in rgb_yuv converter,
878 ** ARGB do NOT work !
880 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '3', '2');
881 p_vout->output.i_rmask = 0x000000ff;
882 p_vout->output.i_gmask = 0x0000ff00;
883 p_vout->output.i_bmask = 0x00ff0000;
884 p_vout->output.i_lrshift = 8;
885 p_vout->output.i_lgshift = 16;
886 p_vout->output.i_lbshift = 24;
889 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '6');
890 # if defined( WORDS_BIGENDIAN )
891 p_vout->output.i_rmask = (0x1fL)<<11;
892 p_vout->output.i_gmask = (0x3fL)<<5;
893 p_vout->output.i_bmask = (0x1fL)<<0;
894 //p_vout->output.i_rshift = 11;
895 //p_vout->output.i_gshift = 5;
896 //p_vout->output.i_bshift = 0;
899 ** FIXME: in little endian mode, following masking is not byte aligned,
900 ** therefore green bits will not be sequentially merged !
902 p_vout->output.i_rmask = (0x1fL)<<0;
903 p_vout->output.i_gmask = (0x3fL)<<5;
904 p_vout->output.i_bmask = (0x1fL)<<11;
905 //p_vout->output.i_rshift = 0;
906 //p_vout->output.i_gshift = 5;
907 //p_vout->output.i_bshift = 11;
910 case D3DFMT_X1R5G5B5:
911 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '5');
912 # if defined( WORDS_BIGENDIAN )
913 p_vout->output.i_rmask = (0x1fL)<<10;
914 p_vout->output.i_gmask = (0x1fL)<<5;
915 p_vout->output.i_bmask = (0x1fL)<<0;
916 //p_vout->output.i_rshift = 10;
917 //p_vout->output.i_gshift = 5;
918 //p_vout->output.i_bshift = 0;
921 ** FIXME: in little endian mode, following masking is not byte aligned,
922 ** therefore green bits will not be sequentially merged !
924 p_vout->output.i_rmask = (0x1fL)<<1;
925 p_vout->output.i_gmask = (0x1fL)<<6;
926 p_vout->output.i_bmask = (0x1fL)<<11;
927 //p_vout->output.i_rshift = 1;
928 //p_vout->output.i_gshift = 5;
929 //p_vout->output.i_bshift = 11;
938 /*****************************************************************************
939 * Direct3DVoutCreatePictures: allocate a vector of identical pictures
940 *****************************************************************************
941 * Each picture has an associated offscreen surface in video memory
942 * depending on hardware capabilities the picture chroma will be as close
943 * as possible to the orginal render chroma to reduce CPU conversion overhead
944 * and delegate this work to video card GPU
945 *****************************************************************************/
946 static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics )
948 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
949 D3DFORMAT format = p_vout->p_sys->d3dpp.BackBufferFormat;
953 I_OUTPUTPICTURES = 0;
956 ** find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
957 ** the requested chroma which is usable by the hardware in an offscreen surface, as they
958 ** typically support more formats than textures
960 format = Direct3DVoutFindFormat(p_vout, p_vout->render.i_chroma, format);
961 if( VLC_SUCCESS != Direct3DVoutSetOutputFormat(p_vout, format) )
963 msg_Err(p_vout, "surface pixel format is not supported.");
967 for( c=0; c<i_num_pics; )
970 LPDIRECT3DSURFACE9 p_d3dsurf;
971 picture_t *p_pic = p_vout->p_picture+c;
973 hr = IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3ddev,
974 p_vout->render.i_width,
975 p_vout->render.i_height,
982 msg_Err(p_vout, "Failed to create picture surface. (hr=0x%lx)", hr);
983 Direct3DVoutReleasePictures(p_vout);
987 /* fill surface with default color */
988 IDirect3DDevice9_ColorFill(p_d3ddev, p_d3dsurf, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
990 /* assign surface to internal structure */
991 p_pic->p_sys = (void *)p_d3dsurf;
993 /* Now that we've got our direct-buffer, we can finish filling in the
994 * picture_t structures */
995 switch( p_vout->output.i_chroma )
997 case VLC_FOURCC('R','G','B','2'):
998 p_pic->p->i_lines = p_vout->output.i_height;
999 p_pic->p->i_visible_lines = p_vout->output.i_height;
1000 p_pic->p->i_pixel_pitch = 1;
1001 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1002 p_pic->p->i_pixel_pitch;
1003 p_pic->i_planes = 1;
1005 case VLC_FOURCC('R','V','1','5'):
1006 case VLC_FOURCC('R','V','1','6'):
1007 p_pic->p->i_lines = p_vout->output.i_height;
1008 p_pic->p->i_visible_lines = p_vout->output.i_height;
1009 p_pic->p->i_pixel_pitch = 2;
1010 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1011 p_pic->p->i_pixel_pitch;
1012 p_pic->i_planes = 1;
1014 case VLC_FOURCC('R','V','2','4'):
1015 p_pic->p->i_lines = p_vout->output.i_height;
1016 p_pic->p->i_visible_lines = p_vout->output.i_height;
1017 p_pic->p->i_pixel_pitch = 3;
1018 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1019 p_pic->p->i_pixel_pitch;
1020 p_pic->i_planes = 1;
1022 case VLC_FOURCC('R','V','3','2'):
1023 p_pic->p->i_lines = p_vout->output.i_height;
1024 p_pic->p->i_visible_lines = p_vout->output.i_height;
1025 p_pic->p->i_pixel_pitch = 4;
1026 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1027 p_pic->p->i_pixel_pitch;
1028 p_pic->i_planes = 1;
1030 case VLC_FOURCC('U','Y','V','Y'):
1031 case VLC_FOURCC('Y','U','Y','2'):
1032 p_pic->p->i_lines = p_vout->output.i_height;
1033 p_pic->p->i_visible_lines = p_vout->output.i_height;
1034 p_pic->p->i_pixel_pitch = 2;
1035 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1036 p_pic->p->i_pixel_pitch;
1037 p_pic->i_planes = 1;
1040 Direct3DVoutReleasePictures(p_vout);
1041 return VLC_EGENERIC;
1043 p_pic->i_status = DESTROYED_PICTURE;
1044 p_pic->i_type = DIRECT_PICTURE;
1045 p_pic->b_slow = VLC_TRUE;
1046 p_pic->pf_lock = Direct3DVoutLockSurface;
1047 p_pic->pf_unlock = Direct3DVoutUnlockSurface;
1048 PP_OUTPUTPICTURE[c] = p_pic;
1050 I_OUTPUTPICTURES = ++c;
1053 msg_Dbg( p_vout, "%u Direct3D pictures created successfully", c );
1058 /*****************************************************************************
1059 * Direct3DVoutReleasePictures: destroy a picture vector
1060 *****************************************************************************
1061 * release all video resources used for pictures
1062 *****************************************************************************/
1063 static void Direct3DVoutReleasePictures( vout_thread_t *p_vout)
1065 size_t i_num_pics = I_OUTPUTPICTURES;
1067 for( c=0; c<i_num_pics; ++c )
1069 picture_t *p_pic = p_vout->p_picture+c;
1072 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1074 p_pic->p_sys = NULL;
1078 IDirect3DSurface9_Release(p_d3dsurf);
1082 msg_Dbg( p_vout, "%u Direct3D pictures released.", c);
1084 I_OUTPUTPICTURES = 0;
1087 /*****************************************************************************
1088 * Direct3DVoutLockSurface: Lock surface and get picture data pointer
1089 *****************************************************************************
1090 * This function locks a surface and get the surface descriptor which amongst
1091 * other things has the pointer to the picture data.
1092 *****************************************************************************/
1093 static int Direct3DVoutLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1096 D3DLOCKED_RECT d3drect;
1097 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1099 if( NULL == p_d3dsurf )
1100 return VLC_EGENERIC;
1102 /* Lock the surface to get a valid pointer to the picture buffer */
1103 hr = IDirect3DSurface9_LockRect(p_d3dsurf, &d3drect, NULL, D3DLOCK_DISCARD);
1106 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1107 return VLC_EGENERIC;
1110 /* fill in buffer info in first plane */
1111 p_pic->p->p_pixels = d3drect.pBits;
1112 p_pic->p->i_pitch = d3drect.Pitch;
1117 /*****************************************************************************
1118 * Direct3DVoutUnlockSurface: Unlock a surface locked by Direct3DLockSurface().
1119 *****************************************************************************/
1120 static int Direct3DVoutUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1123 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1125 if( NULL == p_d3dsurf )
1126 return VLC_EGENERIC;
1128 /* Unlock the Surface */
1129 hr = IDirect3DSurface9_UnlockRect(p_d3dsurf);
1132 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1133 return VLC_EGENERIC;
1138 /*****************************************************************************
1139 * Direct3DVoutCreateScene: allocate and initialize a 3D scene
1140 *****************************************************************************
1141 * for advanced blending/filtering a texture needs be used in a 3D scene.
1142 *****************************************************************************/
1144 static int Direct3DVoutCreateScene( vout_thread_t *p_vout )
1146 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1147 LPDIRECT3DTEXTURE9 p_d3dtex;
1148 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
1153 ** Create a texture for use when rendering a scene
1154 ** for performance reason, texture format is identical to backbuffer
1155 ** which would usually be a RGB format
1157 hr = IDirect3DDevice9_CreateTexture(p_d3ddev,
1158 p_vout->render.i_width,
1159 p_vout->render.i_height,
1161 D3DUSAGE_RENDERTARGET,
1162 p_vout->p_sys->d3dpp.BackBufferFormat,
1168 msg_Err(p_vout, "Failed to create texture. (hr=0x%lx)", hr);
1169 return VLC_EGENERIC;
1173 ** Create a vertex buffer for use when rendering scene
1175 hr = IDirect3DDevice9_CreateVertexBuffer(p_d3ddev,
1176 sizeof(CUSTOMVERTEX)*4,
1178 D3DFVF_CUSTOMVERTEX,
1184 msg_Err(p_vout, "Failed to create vertex buffer. (hr=0x%lx)", hr);
1185 IDirect3DTexture9_Release(p_d3dtex);
1186 return VLC_EGENERIC;
1189 p_vout->p_sys->p_d3dtex = p_d3dtex;
1190 p_vout->p_sys->p_d3dvtc = p_d3dvtc;
1192 // Texture coordinates outside the range [0.0, 1.0] are set
1193 // to the texture color at 0.0 or 1.0, respectively.
1194 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1195 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1197 // Set linear filtering quality
1198 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
1199 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
1201 // set maximum ambient light
1202 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
1205 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_CULLMODE, D3DCULL_NONE);
1207 // Turn off the zbuffer
1208 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ZENABLE, D3DZB_FALSE);
1211 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_LIGHTING, FALSE);
1214 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DITHERENABLE, TRUE);
1217 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_STENCILENABLE, FALSE);
1220 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
1221 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
1222 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
1223 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHATESTENABLE,TRUE);
1224 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAREF, 0x10);
1225 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER);
1227 // Set texture states
1228 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE);
1229 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
1230 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
1232 // turn off alpha operation
1233 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
1235 msg_Dbg( p_vout, "Direct3D scene created successfully");
1240 /*****************************************************************************
1241 * Direct3DVoutReleaseScene
1242 *****************************************************************************/
1243 static void Direct3DVoutReleaseScene( vout_thread_t *p_vout )
1245 LPDIRECT3DTEXTURE9 p_d3dtex = p_vout->p_sys->p_d3dtex;
1246 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1250 IDirect3DVertexBuffer9_Release(p_d3dvtc);
1251 p_vout->p_sys->p_d3dvtc = NULL;
1256 IDirect3DTexture9_Release(p_d3dtex);
1257 p_vout->p_sys->p_d3dtex = NULL;
1259 msg_Dbg( p_vout, "Direct3D scene released successfully");
1262 /*****************************************************************************
1263 * Direct3DVoutRenderDefault: copy picture surface to display back buffer
1264 *****************************************************************************
1265 * This function is intented for lower end video cards, without pixel shader
1266 * support or low video RAM
1267 *****************************************************************************/
1268 static void Direct3DVoutRenderDefault( vout_thread_t *p_vout, picture_t *p_pic )
1270 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1271 LPDIRECT3DSURFACE9 p_d3dsrc, p_d3ddest;
1272 UINT iSwapChain, iSwapChains;
1275 // check if device is still available
1276 hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
1279 if( (D3DERR_DEVICENOTRESET != hr)
1280 || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, 0, 0)) )
1282 // device is not usable at present (lost device, out of video mem ?)
1287 /* retrieve the number of swap chains */
1288 iSwapChains = IDirect3DDevice9_GetNumberOfSwapChains(p_d3ddev);
1289 if( 0 == iSwapChains )
1291 msg_Dbg( p_vout, "no swap chain to render ?");
1295 /* retrieve picture surface */
1296 p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1297 if( NULL == p_d3dsrc )
1299 msg_Dbg( p_vout, "no surface to render ?");
1303 for( iSwapChain=0; iSwapChain < iSwapChains; ++iSwapChain )
1305 /* retrieve swap chain back buffer */
1306 hr = IDirect3DDevice9_GetBackBuffer(p_d3ddev, iSwapChain, 0, D3DBACKBUFFER_TYPE_MONO, &p_d3ddest);
1309 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1313 /* Copy picture surface into texture surface, color space conversion happens here */
1314 hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, NULL, p_d3ddest, NULL, D3DTEXF_NONE);
1315 IDirect3DSurface9_Release(p_d3ddest);
1318 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1324 /*****************************************************************************
1325 * Render: copy picture surface into a texture and render into a scene
1326 *****************************************************************************
1327 * This function is intented for higher end 3D cards, with pixel shader support
1328 * and at least 64 MB of video RAM.
1329 *****************************************************************************/
1330 static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic )
1332 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1333 LPDIRECT3DTEXTURE9 p_d3dtex = p_vout->p_sys->p_d3dtex;
1334 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1335 LPDIRECT3DSURFACE9 p_d3dsrc, p_d3ddest;
1336 CUSTOMVERTEX *p_vertices;
1338 float f_width, f_height;
1340 // check if device is still available
1341 hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
1344 if( (D3DERR_DEVICENOTRESET != hr)
1345 || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, 0, 0)) )
1347 // device is not usable at present (lost device, out of video mem ?)
1352 /* Clear the backbuffer and the zbuffer */
1353 hr = IDirect3DDevice9_Clear( p_d3ddev, 0, NULL, D3DCLEAR_TARGET,
1354 D3DCOLOR_XRGB(0, 255, 0), 1.0f, 0 );
1357 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1361 /* retrieve picture surface */
1362 p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1363 if( NULL == p_d3dsrc )
1365 msg_Dbg( p_vout, "no surface to render ?");
1369 /* retrieve texture top-level surface */
1370 hr = IDirect3DTexture9_GetSurfaceLevel(p_d3dtex, 0, &p_d3ddest);
1373 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1377 /* Copy picture surface into texture surface, color space conversion happens here */
1378 hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, NULL, p_d3ddest, NULL, D3DTEXF_NONE);
1379 IDirect3DSurface9_Release(p_d3ddest);
1382 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1386 /* Update the vertex buffer */
1387 hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (VOID **)(&p_vertices), D3DLOCK_DISCARD);
1390 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1394 /* Setup vertices */
1395 f_width = (float)(p_vout->p_sys->d3dpp.BackBufferWidth);
1396 f_height = (float)(p_vout->p_sys->d3dpp.BackBufferHeight);
1398 p_vertices[0].x = 0.0f; // left
1399 p_vertices[0].y = 0.0f; // top
1400 p_vertices[0].z = 0.0f;
1401 p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1402 p_vertices[0].rhw = 1.0f;
1403 p_vertices[0].tu = 0.0f;
1404 p_vertices[0].tv = 0.0f;
1406 p_vertices[1].x = f_width; // right
1407 p_vertices[1].y = 0.0f; // top
1408 p_vertices[1].z = 0.0f;
1409 p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1410 p_vertices[1].rhw = 1.0f;
1411 p_vertices[1].tu = 1.0f;
1412 p_vertices[1].tv = 0.0f;
1414 p_vertices[2].x = f_width; // right
1415 p_vertices[2].y = f_height; // bottom
1416 p_vertices[2].z = 0.0f;
1417 p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1418 p_vertices[2].rhw = 1.0f;
1419 p_vertices[2].tu = 1.0f;
1420 p_vertices[2].tv = 1.0f;
1422 p_vertices[3].x = 0.0f; // left
1423 p_vertices[3].y = f_height; // bottom
1424 p_vertices[3].z = 0.0f;
1425 p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1426 p_vertices[3].rhw = 1.0f;
1427 p_vertices[3].tu = 0.0f;
1428 p_vertices[3].tv = 1.0f;
1430 hr= IDirect3DVertexBuffer9_Unlock(p_d3dvtc);
1433 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1438 hr = IDirect3DDevice9_BeginScene(p_d3ddev);
1441 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1445 // Setup our texture. Using textures introduces the texture stage states,
1446 // which govern how textures get blended together (in the case of multiple
1447 // textures) and lighting information. In this case, we are modulating
1448 // (blending) our texture with the diffuse color of the vertices.
1449 hr = IDirect3DDevice9_SetTexture(p_d3ddev, 0, (LPDIRECT3DBASETEXTURE9)p_d3dtex);
1452 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1453 IDirect3DDevice9_EndScene(p_d3ddev);
1457 // Render the vertex buffer contents
1458 hr = IDirect3DDevice9_SetStreamSource(p_d3ddev, 0, p_d3dvtc, 0, sizeof(CUSTOMVERTEX));
1461 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1462 IDirect3DDevice9_EndScene(p_d3ddev);
1466 // we use FVF instead of vertex shader
1467 hr = IDirect3DDevice9_SetVertexShader(p_d3ddev, NULL);
1470 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1471 IDirect3DDevice9_EndScene(p_d3ddev);
1475 hr = IDirect3DDevice9_SetFVF(p_d3ddev, D3DFVF_CUSTOMVERTEX);
1478 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1479 IDirect3DDevice9_EndScene(p_d3ddev);
1484 hr = IDirect3DDevice9_DrawPrimitive(p_d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
1487 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1488 IDirect3DDevice9_EndScene(p_d3ddev);
1493 hr = IDirect3DDevice9_EndScene(p_d3ddev);
1496 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);