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() */
42 #include <vlc_interface.h>
50 /*****************************************************************************
52 *****************************************************************************/
53 static int OpenVideo ( vlc_object_t * );
54 static void CloseVideo ( vlc_object_t * );
56 static int Init ( vout_thread_t * );
57 static void End ( vout_thread_t * );
58 static int Manage ( vout_thread_t * );
59 static void Display ( vout_thread_t *, picture_t * );
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('I','4','2','2'):
818 case VLC_FOURCC('Y','V','1','2'):
820 /* typically 3D textures don't support planar format
821 ** fallback to packed version and use pixel
822 ** shader or CPU for the conversion
824 static const D3DFORMAT formats[] =
825 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
826 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
828 case VLC_FOURCC('Y','U','Y','2'):
829 case VLC_FOURCC('Y','U','N','V'):
831 static const D3DFORMAT formats[] =
832 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
833 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
835 case VLC_FOURCC('R', 'V', '1', '5'):
837 static const D3DFORMAT formats[] =
839 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
841 case VLC_FOURCC('R', 'V', '1', '6'):
843 static const D3DFORMAT formats[] =
845 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
847 case VLC_FOURCC('R', 'V', '2', '4'):
849 static const D3DFORMAT formats[] =
850 { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
851 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
853 case VLC_FOURCC('R', 'V', '3', '2'):
855 static const D3DFORMAT formats[] =
856 { D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8 };
857 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
862 return D3DFMT_UNKNOWN;
865 static int Direct3DVoutSetOutputFormat(vout_thread_t *p_vout, D3DFORMAT format)
870 p_vout->output.i_chroma = VLC_FOURCC('Y', 'U', 'Y', '2');
873 p_vout->output.i_chroma = VLC_FOURCC('U', 'Y', 'V', 'Y');
875 case D3DFMT_X8R8G8B8:
876 case D3DFMT_A8R8G8B8:
878 ** FIXME: some custom masks are not handled properly in rgb_yuv converter,
879 ** ARGB do NOT work !
881 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '3', '2');
882 p_vout->output.i_rmask = 0x000000ff;
883 p_vout->output.i_gmask = 0x0000ff00;
884 p_vout->output.i_bmask = 0x00ff0000;
885 p_vout->output.i_lrshift = 8;
886 p_vout->output.i_lgshift = 16;
887 p_vout->output.i_lbshift = 24;
890 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '6');
891 # if defined( WORDS_BIGENDIAN )
892 p_vout->output.i_rmask = (0x1fL)<<11;
893 p_vout->output.i_gmask = (0x3fL)<<5;
894 p_vout->output.i_bmask = (0x1fL)<<0;
895 //p_vout->output.i_rshift = 11;
896 //p_vout->output.i_gshift = 5;
897 //p_vout->output.i_bshift = 0;
900 ** FIXME: in little endian mode, following masking is not byte aligned,
901 ** therefore green bits will not be sequentially merged !
903 p_vout->output.i_rmask = (0x1fL)<<0;
904 p_vout->output.i_gmask = (0x3fL)<<5;
905 p_vout->output.i_bmask = (0x1fL)<<11;
906 //p_vout->output.i_rshift = 0;
907 //p_vout->output.i_gshift = 5;
908 //p_vout->output.i_bshift = 11;
911 case D3DFMT_X1R5G5B5:
912 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '5');
913 # if defined( WORDS_BIGENDIAN )
914 p_vout->output.i_rmask = (0x1fL)<<10;
915 p_vout->output.i_gmask = (0x1fL)<<5;
916 p_vout->output.i_bmask = (0x1fL)<<0;
917 //p_vout->output.i_rshift = 10;
918 //p_vout->output.i_gshift = 5;
919 //p_vout->output.i_bshift = 0;
922 ** FIXME: in little endian mode, following masking is not byte aligned,
923 ** therefore green bits will not be sequentially merged !
925 p_vout->output.i_rmask = (0x1fL)<<1;
926 p_vout->output.i_gmask = (0x1fL)<<6;
927 p_vout->output.i_bmask = (0x1fL)<<11;
928 //p_vout->output.i_rshift = 1;
929 //p_vout->output.i_gshift = 5;
930 //p_vout->output.i_bshift = 11;
939 /*****************************************************************************
940 * Direct3DVoutCreatePictures: allocate a vector of identical pictures
941 *****************************************************************************
942 * Each picture has an associated offscreen surface in video memory
943 * depending on hardware capabilities the picture chroma will be as close
944 * as possible to the orginal render chroma to reduce CPU conversion overhead
945 * and delegate this work to video card GPU
946 *****************************************************************************/
947 static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics )
949 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
950 D3DFORMAT format = p_vout->p_sys->d3dpp.BackBufferFormat;
954 I_OUTPUTPICTURES = 0;
957 ** find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
958 ** the requested chroma which is usable by the hardware in an offscreen surface, as they
959 ** typically support more formats than textures
961 format = Direct3DVoutFindFormat(p_vout, p_vout->render.i_chroma, format);
962 if( VLC_SUCCESS != Direct3DVoutSetOutputFormat(p_vout, format) )
964 msg_Err(p_vout, "surface pixel format is not supported.");
968 for( c=0; c<i_num_pics; )
971 LPDIRECT3DSURFACE9 p_d3dsurf;
972 picture_t *p_pic = p_vout->p_picture+c;
974 hr = IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3ddev,
975 p_vout->render.i_width,
976 p_vout->render.i_height,
983 msg_Err(p_vout, "Failed to create picture surface. (hr=0x%lx)", hr);
984 Direct3DVoutReleasePictures(p_vout);
988 /* fill surface with default color */
989 IDirect3DDevice9_ColorFill(p_d3ddev, p_d3dsurf, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
991 /* assign surface to internal structure */
992 p_pic->p_sys = (void *)p_d3dsurf;
994 /* Now that we've got our direct-buffer, we can finish filling in the
995 * picture_t structures */
996 switch( p_vout->output.i_chroma )
998 case VLC_FOURCC('R','G','B','2'):
999 p_pic->p->i_lines = p_vout->output.i_height;
1000 p_pic->p->i_visible_lines = p_vout->output.i_height;
1001 p_pic->p->i_pixel_pitch = 1;
1002 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1003 p_pic->p->i_pixel_pitch;
1004 p_pic->i_planes = 1;
1006 case VLC_FOURCC('R','V','1','5'):
1007 case VLC_FOURCC('R','V','1','6'):
1008 p_pic->p->i_lines = p_vout->output.i_height;
1009 p_pic->p->i_visible_lines = p_vout->output.i_height;
1010 p_pic->p->i_pixel_pitch = 2;
1011 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1012 p_pic->p->i_pixel_pitch;
1013 p_pic->i_planes = 1;
1015 case VLC_FOURCC('R','V','2','4'):
1016 p_pic->p->i_lines = p_vout->output.i_height;
1017 p_pic->p->i_visible_lines = p_vout->output.i_height;
1018 p_pic->p->i_pixel_pitch = 3;
1019 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1020 p_pic->p->i_pixel_pitch;
1021 p_pic->i_planes = 1;
1023 case VLC_FOURCC('R','V','3','2'):
1024 p_pic->p->i_lines = p_vout->output.i_height;
1025 p_pic->p->i_visible_lines = p_vout->output.i_height;
1026 p_pic->p->i_pixel_pitch = 4;
1027 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1028 p_pic->p->i_pixel_pitch;
1029 p_pic->i_planes = 1;
1031 case VLC_FOURCC('U','Y','V','Y'):
1032 case VLC_FOURCC('Y','U','Y','2'):
1033 p_pic->p->i_lines = p_vout->output.i_height;
1034 p_pic->p->i_visible_lines = p_vout->output.i_height;
1035 p_pic->p->i_pixel_pitch = 2;
1036 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1037 p_pic->p->i_pixel_pitch;
1038 p_pic->i_planes = 1;
1041 Direct3DVoutReleasePictures(p_vout);
1042 return VLC_EGENERIC;
1044 p_pic->i_status = DESTROYED_PICTURE;
1045 p_pic->i_type = DIRECT_PICTURE;
1046 p_pic->b_slow = VLC_TRUE;
1047 p_pic->pf_lock = Direct3DVoutLockSurface;
1048 p_pic->pf_unlock = Direct3DVoutUnlockSurface;
1049 PP_OUTPUTPICTURE[c] = p_pic;
1051 I_OUTPUTPICTURES = ++c;
1054 msg_Dbg( p_vout, "%u Direct3D pictures created successfully", c );
1059 /*****************************************************************************
1060 * Direct3DVoutReleasePictures: destroy a picture vector
1061 *****************************************************************************
1062 * release all video resources used for pictures
1063 *****************************************************************************/
1064 static void Direct3DVoutReleasePictures( vout_thread_t *p_vout)
1066 size_t i_num_pics = I_OUTPUTPICTURES;
1068 for( c=0; c<i_num_pics; ++c )
1070 picture_t *p_pic = p_vout->p_picture+c;
1073 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1075 p_pic->p_sys = NULL;
1079 IDirect3DSurface9_Release(p_d3dsurf);
1083 msg_Dbg( p_vout, "%u Direct3D pictures released.", c);
1085 I_OUTPUTPICTURES = 0;
1088 /*****************************************************************************
1089 * Direct3DVoutLockSurface: Lock surface and get picture data pointer
1090 *****************************************************************************
1091 * This function locks a surface and get the surface descriptor which amongst
1092 * other things has the pointer to the picture data.
1093 *****************************************************************************/
1094 static int Direct3DVoutLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1097 D3DLOCKED_RECT d3drect;
1098 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1100 if( NULL == p_d3dsurf )
1101 return VLC_EGENERIC;
1103 /* Lock the surface to get a valid pointer to the picture buffer */
1104 hr = IDirect3DSurface9_LockRect(p_d3dsurf, &d3drect, NULL, D3DLOCK_DISCARD);
1107 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1108 return VLC_EGENERIC;
1111 /* fill in buffer info in first plane */
1112 p_pic->p->p_pixels = d3drect.pBits;
1113 p_pic->p->i_pitch = d3drect.Pitch;
1118 /*****************************************************************************
1119 * Direct3DVoutUnlockSurface: Unlock a surface locked by Direct3DLockSurface().
1120 *****************************************************************************/
1121 static int Direct3DVoutUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1124 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1126 if( NULL == p_d3dsurf )
1127 return VLC_EGENERIC;
1129 /* Unlock the Surface */
1130 hr = IDirect3DSurface9_UnlockRect(p_d3dsurf);
1133 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1134 return VLC_EGENERIC;
1139 /*****************************************************************************
1140 * Direct3DVoutCreateScene: allocate and initialize a 3D scene
1141 *****************************************************************************
1142 * for advanced blending/filtering a texture needs be used in a 3D scene.
1143 *****************************************************************************/
1145 static int Direct3DVoutCreateScene( vout_thread_t *p_vout )
1147 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1148 LPDIRECT3DTEXTURE9 p_d3dtex;
1149 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
1154 ** Create a texture for use when rendering a scene
1155 ** for performance reason, texture format is identical to backbuffer
1156 ** which would usually be a RGB format
1158 hr = IDirect3DDevice9_CreateTexture(p_d3ddev,
1159 p_vout->render.i_width,
1160 p_vout->render.i_height,
1162 D3DUSAGE_RENDERTARGET,
1163 p_vout->p_sys->d3dpp.BackBufferFormat,
1169 msg_Err(p_vout, "Failed to create texture. (hr=0x%lx)", hr);
1170 return VLC_EGENERIC;
1174 ** Create a vertex buffer for use when rendering scene
1176 hr = IDirect3DDevice9_CreateVertexBuffer(p_d3ddev,
1177 sizeof(CUSTOMVERTEX)*4,
1179 D3DFVF_CUSTOMVERTEX,
1185 msg_Err(p_vout, "Failed to create vertex buffer. (hr=0x%lx)", hr);
1186 IDirect3DTexture9_Release(p_d3dtex);
1187 return VLC_EGENERIC;
1190 p_vout->p_sys->p_d3dtex = p_d3dtex;
1191 p_vout->p_sys->p_d3dvtc = p_d3dvtc;
1193 // Texture coordinates outside the range [0.0, 1.0] are set
1194 // to the texture color at 0.0 or 1.0, respectively.
1195 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1196 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1198 // Set linear filtering quality
1199 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
1200 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
1202 // set maximum ambient light
1203 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
1206 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_CULLMODE, D3DCULL_NONE);
1208 // Turn off the zbuffer
1209 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ZENABLE, D3DZB_FALSE);
1212 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_LIGHTING, FALSE);
1215 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DITHERENABLE, TRUE);
1218 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_STENCILENABLE, FALSE);
1221 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
1222 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
1223 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
1224 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHATESTENABLE,TRUE);
1225 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAREF, 0x10);
1226 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER);
1228 // Set texture states
1229 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE);
1230 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
1231 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
1233 // turn off alpha operation
1234 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
1236 msg_Dbg( p_vout, "Direct3D scene created successfully");
1241 /*****************************************************************************
1242 * Direct3DVoutReleaseScene
1243 *****************************************************************************/
1244 static void Direct3DVoutReleaseScene( vout_thread_t *p_vout )
1246 LPDIRECT3DTEXTURE9 p_d3dtex = p_vout->p_sys->p_d3dtex;
1247 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1251 IDirect3DVertexBuffer9_Release(p_d3dvtc);
1252 p_vout->p_sys->p_d3dvtc = NULL;
1257 IDirect3DTexture9_Release(p_d3dtex);
1258 p_vout->p_sys->p_d3dtex = NULL;
1260 msg_Dbg( p_vout, "Direct3D scene released successfully");
1263 /*****************************************************************************
1264 * Direct3DVoutRenderDefault: copy picture surface to display back buffer
1265 *****************************************************************************
1266 * This function is intented for lower end video cards, without pixel shader
1267 * support or low video RAM
1268 *****************************************************************************/
1269 static void Direct3DVoutRenderDefault( vout_thread_t *p_vout, picture_t *p_pic )
1271 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1272 LPDIRECT3DSURFACE9 p_d3dsrc, p_d3ddest;
1273 UINT iSwapChain, iSwapChains;
1276 // check if device is still available
1277 hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
1280 if( (D3DERR_DEVICENOTRESET != hr)
1281 || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, 0, 0)) )
1283 // device is not usable at present (lost device, out of video mem ?)
1288 /* retrieve the number of swap chains */
1289 iSwapChains = IDirect3DDevice9_GetNumberOfSwapChains(p_d3ddev);
1290 if( 0 == iSwapChains )
1292 msg_Dbg( p_vout, "no swap chain to render ?");
1296 /* retrieve picture surface */
1297 p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1298 if( NULL == p_d3dsrc )
1300 msg_Dbg( p_vout, "no surface to render ?");
1304 for( iSwapChain=0; iSwapChain < iSwapChains; ++iSwapChain )
1306 /* retrieve swap chain back buffer */
1307 hr = IDirect3DDevice9_GetBackBuffer(p_d3ddev, iSwapChain, 0, D3DBACKBUFFER_TYPE_MONO, &p_d3ddest);
1310 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1314 /* Copy picture surface into texture surface, color space conversion happens here */
1315 hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, NULL, p_d3ddest, NULL, D3DTEXF_NONE);
1316 IDirect3DSurface9_Release(p_d3ddest);
1319 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1325 /*****************************************************************************
1326 * Render: copy picture surface into a texture and render into a scene
1327 *****************************************************************************
1328 * This function is intented for higher end 3D cards, with pixel shader support
1329 * and at least 64 MB of video RAM.
1330 *****************************************************************************/
1331 static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic )
1333 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1334 LPDIRECT3DTEXTURE9 p_d3dtex = p_vout->p_sys->p_d3dtex;
1335 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1336 LPDIRECT3DSURFACE9 p_d3dsrc, p_d3ddest;
1337 CUSTOMVERTEX *p_vertices;
1339 float f_width, f_height;
1341 // check if device is still available
1342 hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
1345 if( (D3DERR_DEVICENOTRESET != hr)
1346 || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, 0, 0)) )
1348 // device is not usable at present (lost device, out of video mem ?)
1353 /* Clear the backbuffer and the zbuffer */
1354 hr = IDirect3DDevice9_Clear( p_d3ddev, 0, NULL, D3DCLEAR_TARGET,
1355 D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0 );
1358 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1362 /* retrieve picture surface */
1363 p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1364 if( NULL == p_d3dsrc )
1366 msg_Dbg( p_vout, "no surface to render ?");
1370 /* retrieve texture top-level surface */
1371 hr = IDirect3DTexture9_GetSurfaceLevel(p_d3dtex, 0, &p_d3ddest);
1374 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1378 /* Copy picture surface into texture surface, color space conversion happens here */
1379 hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, NULL, p_d3ddest, NULL, D3DTEXF_NONE);
1380 IDirect3DSurface9_Release(p_d3ddest);
1383 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1387 /* Update the vertex buffer */
1388 hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (VOID **)(&p_vertices), D3DLOCK_DISCARD);
1391 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1395 /* Setup vertices */
1396 f_width = (float)(p_vout->p_sys->d3dpp.BackBufferWidth);
1397 f_height = (float)(p_vout->p_sys->d3dpp.BackBufferHeight);
1399 p_vertices[0].x = 0.0f; // left
1400 p_vertices[0].y = 0.0f; // top
1401 p_vertices[0].z = 0.0f;
1402 p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1403 p_vertices[0].rhw = 1.0f;
1404 p_vertices[0].tu = 0.0f;
1405 p_vertices[0].tv = 0.0f;
1407 p_vertices[1].x = f_width; // right
1408 p_vertices[1].y = 0.0f; // top
1409 p_vertices[1].z = 0.0f;
1410 p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1411 p_vertices[1].rhw = 1.0f;
1412 p_vertices[1].tu = 1.0f;
1413 p_vertices[1].tv = 0.0f;
1415 p_vertices[2].x = f_width; // right
1416 p_vertices[2].y = f_height; // bottom
1417 p_vertices[2].z = 0.0f;
1418 p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1419 p_vertices[2].rhw = 1.0f;
1420 p_vertices[2].tu = 1.0f;
1421 p_vertices[2].tv = 1.0f;
1423 p_vertices[3].x = 0.0f; // left
1424 p_vertices[3].y = f_height; // bottom
1425 p_vertices[3].z = 0.0f;
1426 p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1427 p_vertices[3].rhw = 1.0f;
1428 p_vertices[3].tu = 0.0f;
1429 p_vertices[3].tv = 1.0f;
1431 hr= IDirect3DVertexBuffer9_Unlock(p_d3dvtc);
1434 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1439 hr = IDirect3DDevice9_BeginScene(p_d3ddev);
1442 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1446 // Setup our texture. Using textures introduces the texture stage states,
1447 // which govern how textures get blended together (in the case of multiple
1448 // textures) and lighting information. In this case, we are modulating
1449 // (blending) our texture with the diffuse color of the vertices.
1450 hr = IDirect3DDevice9_SetTexture(p_d3ddev, 0, (LPDIRECT3DBASETEXTURE9)p_d3dtex);
1453 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1454 IDirect3DDevice9_EndScene(p_d3ddev);
1458 // Render the vertex buffer contents
1459 hr = IDirect3DDevice9_SetStreamSource(p_d3ddev, 0, p_d3dvtc, 0, sizeof(CUSTOMVERTEX));
1462 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1463 IDirect3DDevice9_EndScene(p_d3ddev);
1467 // we use FVF instead of vertex shader
1468 hr = IDirect3DDevice9_SetVertexShader(p_d3ddev, NULL);
1471 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1472 IDirect3DDevice9_EndScene(p_d3ddev);
1476 hr = IDirect3DDevice9_SetFVF(p_d3ddev, D3DFVF_CUSTOMVERTEX);
1479 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1480 IDirect3DDevice9_EndScene(p_d3ddev);
1485 hr = IDirect3DDevice9_DrawPrimitive(p_d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
1488 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1489 IDirect3DDevice9_EndScene(p_d3ddev);
1494 hr = IDirect3DDevice9_EndScene(p_d3ddev);
1497 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);