1 /*****************************************************************************
2 * direct3d.c: Windows Direct3D video output module
3 *****************************************************************************
4 * Copyright (C) 2006 the VideoLAN team
7 * Authors: Damien Fouilleul <damienf@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
27 * This plugin will use YUV surface if supported, using YUV will result in
28 * the best video quality (hardware filering when rescaling the picture)
29 * and the fastest display as it requires less processing.
31 * If YUV overlay is not supported this plugin will use RGB offscreen video
32 * surfaces that will be blitted onto the primary surface (display) to
33 * effectively display the pictures.
35 *****************************************************************************/
36 #include <errno.h> /* ENOMEM */
37 #include <stdlib.h> /* free() */
38 #include <string.h> /* strerror() */
41 #include <vlc_interface.h>
42 #include <vlc_playlist.h>
50 /*****************************************************************************
52 *****************************************************************************/
53 static int OpenVideo ( vlc_object_t * );
54 static void CloseVideo ( vlc_object_t * );
56 static int Init ( vout_thread_t * );
57 static void End ( vout_thread_t * );
58 static int Manage ( vout_thread_t * );
59 static void Display ( vout_thread_t *, picture_t * );
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 Direct3DVoutRenderSurface ( 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 static int get_capability_for_osversion()
88 winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
90 if( GetVersionEx(&winVer) )
92 if( winVer.dwMajorVersion > 5 )
94 /* Windows Vista or above, make this module the default */
98 /* Windows XP or lower, make sure this module isn't the default */
103 set_shortname( "Direct3D" );
104 set_category( CAT_VIDEO );
105 set_subcategory( SUBCAT_VIDEO_VOUT );
106 set_description( _("DirectX 3D video output") );
107 set_capability( "video output", get_capability_for_osversion() );
108 add_shortcut( "direct3d" );
109 set_callbacks( OpenVideo, CloseVideo );
111 /* FIXME: Hack to avoid unregistering our window class */
112 linked_with_a_crap_library_which_uses_atexit( );
116 /* check if we registered a window class because we need to
119 if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
120 UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
123 /*****************************************************************************
125 *****************************************************************************
126 *****************************************************************************/
129 FLOAT x,y,z; // vertex untransformed position
130 FLOAT rhw; // eye distance
131 D3DCOLOR diffuse; // diffuse color
132 FLOAT tu, tv; // texture relative coordinates
135 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
137 /*****************************************************************************
138 * OpenVideo: allocate DirectX video thread output method
139 *****************************************************************************
140 * This function allocates and initialize the Direct3D vout method.
141 *****************************************************************************/
142 static int OpenVideo( vlc_object_t *p_this )
144 vout_thread_t * p_vout = (vout_thread_t *)p_this;
147 /* Allocate structure */
148 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
149 if( p_vout->p_sys == NULL )
151 msg_Err( p_vout, "out of memory" );
154 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
156 if( VLC_SUCCESS != Direct3DVoutCreate( p_vout ) )
158 msg_Err( p_vout, "Direct3D could not be initialized !");
162 /* Initialisations */
163 p_vout->pf_init = Init;
164 p_vout->pf_end = End;
165 p_vout->pf_manage = Manage;
166 p_vout->pf_render = Direct3DVoutRenderScene;
167 p_vout->pf_display = Display;
169 p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
170 p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
171 p_vout->p_sys->i_changes = 0;
172 p_vout->p_sys->b_wallpaper = 0;
173 vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
174 SetRectEmpty( &p_vout->p_sys->rect_display );
175 SetRectEmpty( &p_vout->p_sys->rect_parent );
177 var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
178 var_Create( p_vout, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
179 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
180 var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
182 p_vout->p_sys->b_cursor_hidden = 0;
183 p_vout->p_sys->i_lastmoved = mdate();
185 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
186 var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
188 /* Set main window's size */
189 p_vout->p_sys->i_window_width = p_vout->i_window_width;
190 p_vout->p_sys->i_window_height = p_vout->i_window_height;
192 /* Create the DirectXEventThread, this thread is created by us to isolate
193 * the Win32 PeekMessage function calls. We want to do this because
194 * Windows can stay blocked inside this call for a long time, and when
195 * this happens it thus blocks vlc's video_output thread.
196 * DirectXEventThread will take care of the creation of the video
197 * window (because PeekMessage has to be called from the same thread which
198 * created the window). */
199 msg_Dbg( p_vout, "creating DirectXEventThread" );
200 p_vout->p_sys->p_event =
201 vlc_object_create( p_vout, sizeof(event_thread_t) );
202 p_vout->p_sys->p_event->p_vout = p_vout;
203 if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
204 E_(DirectXEventThread), 0, 1 ) )
206 msg_Err( p_vout, "cannot create DirectXEventThread" );
207 vlc_object_destroy( p_vout->p_sys->p_event );
208 p_vout->p_sys->p_event = NULL;
212 if( p_vout->p_sys->p_event->b_error )
214 msg_Err( p_vout, "DirectXEventThread failed" );
218 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
220 msg_Dbg( p_vout, "DirectXEventThread running" );
222 /* Variable to indicate if the window should be on top of others */
223 /* Trigger a callback right now */
224 var_Get( p_vout, "video-on-top", &val );
225 var_Set( p_vout, "video-on-top", val );
227 /* disable screensaver by temporarily changing system settings */
228 p_vout->p_sys->i_spi_lowpowertimeout = 0;
229 p_vout->p_sys->i_spi_powerofftimeout = 0;
230 p_vout->p_sys->i_spi_screensavetimeout = 0;
231 var_Get( p_vout, "disable-screensaver", &val);
233 msg_Dbg(p_vout, "disabling screen saver");
234 SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
235 0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
236 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
237 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
239 SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
240 &(p_vout->p_sys->i_spi_powerofftimeout), 0);
241 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
242 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
244 SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
245 &(p_vout->p_sys->i_spi_screensavetimeout), 0);
246 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
247 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
253 CloseVideo( VLC_OBJECT(p_vout) );
257 /*****************************************************************************
258 * CloseVideo: destroy Sys video thread output method
259 *****************************************************************************
260 * Terminate an output method created by Create
261 *****************************************************************************/
262 static void CloseVideo( vlc_object_t *p_this )
264 vout_thread_t * p_vout = (vout_thread_t *)p_this;
266 Direct3DVoutRelease( p_vout );
268 if( p_vout->p_sys->p_event )
270 vlc_object_detach( p_vout->p_sys->p_event );
272 /* Kill DirectXEventThread */
273 p_vout->p_sys->p_event->b_die = VLC_TRUE;
275 /* we need to be sure DirectXEventThread won't stay stuck in
276 * GetMessage, so we send a fake message */
277 if( p_vout->p_sys->hwnd )
279 PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
282 vlc_thread_join( p_vout->p_sys->p_event );
283 vlc_object_destroy( p_vout->p_sys->p_event );
286 vlc_mutex_destroy( &p_vout->p_sys->lock );
288 /* restore screensaver system settings */
289 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
290 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
291 p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
293 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
294 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
295 p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
297 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
298 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
299 p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
304 free( p_vout->p_sys );
305 p_vout->p_sys = NULL;
309 /*****************************************************************************
310 * Init: initialize Direct3D video thread output method
311 *****************************************************************************/
312 static int Init( vout_thread_t *p_vout )
317 var_Get( p_vout, "directx-hw-yuv", &val );
318 p_vout->p_sys->b_hw_yuv = val.b_bool;
320 /* Initialise Direct3D */
321 if( VLC_SUCCESS != Direct3DVoutOpen( p_vout ) )
323 msg_Err( p_vout, "cannot initialize Direct3D" );
327 /* Initialize the output structure.
328 * Since Direct3D can do rescaling for us, stick to the default
329 * coordinates and aspect. */
330 p_vout->output.i_width = p_vout->render.i_width;
331 p_vout->output.i_height = p_vout->render.i_height;
332 p_vout->output.i_aspect = p_vout->render.i_aspect;
333 p_vout->fmt_out = p_vout->fmt_in;
334 E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
336 /* create picture pool */
337 i_ret = Direct3DVoutCreatePictures(p_vout, 1);
338 if( VLC_SUCCESS != i_ret )
340 msg_Err(p_vout, "Direct3D picture pool initialization failed !");
345 i_ret = Direct3DVoutCreateScene(p_vout);
346 if( VLC_SUCCESS != i_ret )
348 msg_Err(p_vout, "Direct3D scene initialization failed !");
349 Direct3DVoutReleasePictures(p_vout);
353 /* Change the window title bar text */
354 PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
356 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
360 /*****************************************************************************
361 * End: terminate Sys video thread output method
362 *****************************************************************************
363 * Terminate an output method created by Create.
364 * It is called at the end of the thread.
365 *****************************************************************************/
366 static void End( vout_thread_t *p_vout )
368 Direct3DVoutReleaseScene(p_vout);
369 Direct3DVoutReleasePictures(p_vout);
370 Direct3DVoutClose( p_vout );
373 /*****************************************************************************
374 * Manage: handle Sys events
375 *****************************************************************************
376 * This function should be called regularly by the video output thread.
377 * It returns a non null value if an error occurred.
378 *****************************************************************************/
379 static int Manage( vout_thread_t *p_vout )
381 WINDOWPLACEMENT window_placement;
383 /* If we do not control our window, we check for geometry changes
384 * ourselves because the parent might not send us its events. */
385 vlc_mutex_lock( &p_vout->p_sys->lock );
386 if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
391 vlc_mutex_unlock( &p_vout->p_sys->lock );
393 GetClientRect( p_vout->p_sys->hparent, &rect_parent );
394 point.x = point.y = 0;
395 ClientToScreen( p_vout->p_sys->hparent, &point );
396 OffsetRect( &rect_parent, point.x, point.y );
398 if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
400 p_vout->p_sys->rect_parent = rect_parent;
402 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
403 rect_parent.right - rect_parent.left,
404 rect_parent.bottom - rect_parent.top, 0 );
409 vlc_mutex_unlock( &p_vout->p_sys->lock );
415 if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
417 #if 0 /* need that when bicubic filter is available */
421 GetClientRect(p_vout->p_sys->hvideownd, &rect);
422 width = rect.right-rect.left;
423 height = rect.bottom-rect.top;
425 if( (width != p_vout->p_sys->d3dpp.BackBufferWidth)
426 || (height != p_vout->p_sys->d3dpp.BackBufferHeight) )
428 msg_Dbg(p_vout, "resizing device back buffers to (%lux%lu)", width, height);
429 // need to reset D3D device to resize back buffer
430 if( VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, width, height) )
434 p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
437 /* Check for cropping / aspect changes */
438 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
439 p_vout->i_changes & VOUT_ASPECT_CHANGE )
441 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
442 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
444 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
445 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
446 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
447 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
448 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
449 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
450 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
451 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
452 E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
455 /* We used to call the Win32 PeekMessage function here to read the window
456 * messages. But since window can stay blocked into this function for a
457 * long time (for example when you move your window on the screen), I
458 * decided to isolate PeekMessage in another thread. */
463 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
464 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
467 HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ?
468 p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd;
470 p_vout->b_fullscreen = ! p_vout->b_fullscreen;
472 /* We need to switch between Maximized and Normal sized window */
473 window_placement.length = sizeof(WINDOWPLACEMENT);
474 GetWindowPlacement( hwnd, &window_placement );
475 if( p_vout->b_fullscreen )
477 /* Change window style, no borders and no title bar */
478 int i_style = WS_CLIPCHILDREN | WS_VISIBLE;
479 SetWindowLong( hwnd, GWL_STYLE, i_style );
481 if( p_vout->p_sys->hparent )
483 /* Retrieve current window position so fullscreen will happen
484 * on the right screen */
487 ClientToScreen( p_vout->p_sys->hwnd, &point );
488 GetClientRect( p_vout->p_sys->hwnd, &rect );
489 SetWindowPos( hwnd, 0, point.x, point.y,
490 rect.right, rect.bottom,
491 SWP_NOZORDER|SWP_FRAMECHANGED );
492 GetWindowPlacement( hwnd, &window_placement );
495 /* Maximize window */
496 window_placement.showCmd = SW_SHOWMAXIMIZED;
497 SetWindowPlacement( hwnd, &window_placement );
498 SetWindowPos( hwnd, 0, 0, 0, 0, 0,
499 SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
501 if( p_vout->p_sys->hparent )
504 GetClientRect( hwnd, &rect );
505 SetParent( p_vout->p_sys->hwnd, hwnd );
506 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
507 rect.right, rect.bottom,
508 SWP_NOZORDER|SWP_FRAMECHANGED );
511 SetForegroundWindow( hwnd );
515 /* Change window style, no borders and no title bar */
516 SetWindowLong( hwnd, GWL_STYLE, p_vout->p_sys->i_window_style );
519 window_placement.showCmd = SW_SHOWNORMAL;
520 SetWindowPlacement( hwnd, &window_placement );
521 SetWindowPos( hwnd, 0, 0, 0, 0, 0,
522 SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
524 if( p_vout->p_sys->hparent )
527 GetClientRect( p_vout->p_sys->hparent, &rect );
528 SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
529 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
530 rect.right, rect.bottom,
531 SWP_NOZORDER|SWP_FRAMECHANGED );
533 ShowWindow( hwnd, SW_HIDE );
534 SetForegroundWindow( p_vout->p_sys->hparent );
537 /* Make sure the mouse cursor is displayed */
538 PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
541 /* Update the object variable and trigger callback */
542 val.b_bool = p_vout->b_fullscreen;
543 var_Set( p_vout, "fullscreen", val );
545 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
546 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
552 if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
553 (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 )
558 /* Hide the cursor only if it is inside our window */
559 GetCursorPos( &point );
560 hwnd = WindowFromPoint(point);
561 if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
563 PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
567 p_vout->p_sys->i_lastmoved = mdate();
572 * "Always on top" status change
574 if( p_vout->p_sys->b_on_top_change )
577 HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
579 var_Get( p_vout, "video-on-top", &val );
581 /* Set the window on top if necessary */
582 if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
585 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
586 MF_BYCOMMAND | MFS_CHECKED );
587 SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
588 SWP_NOSIZE | SWP_NOMOVE );
591 /* The window shouldn't be on top */
592 if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
595 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
596 MF_BYCOMMAND | MFS_UNCHECKED );
597 SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
598 SWP_NOSIZE | SWP_NOMOVE );
601 p_vout->p_sys->b_on_top_change = VLC_FALSE;
604 /* Check if the event thread is still running */
605 if( p_vout->p_sys->p_event->b_die )
607 return VLC_EGENERIC; /* exit */
613 /*****************************************************************************
614 * Display: displays previously rendered output
615 *****************************************************************************
616 * This function sends the currently rendered image to the display, wait until
617 * it is displayed and switch the two rendering buffers, preparing next frame.
618 *****************************************************************************/
619 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
621 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
622 // Present the back buffer contents to the display
623 // stretching and filtering happens here
624 HRESULT hr = IDirect3DDevice9_Present(p_d3ddev, NULL, NULL, NULL, NULL);
626 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
629 /*****************************************************************************
630 * DirectD3DVoutCreate: Initialize and instance of Direct3D9
631 *****************************************************************************
632 * This function initialize Direct3D and analyze available resources from
634 *****************************************************************************/
635 static int Direct3DVoutCreate( vout_thread_t *p_vout )
638 LPDIRECT3D9 p_d3dobj;
641 LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
643 p_vout->p_sys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
644 if( NULL == p_vout->p_sys->hd3d9_dll )
646 msg_Warn( p_vout, "cannot load d3d9.dll, aborting" );
651 (void *)GetProcAddress( p_vout->p_sys->hd3d9_dll,
652 TEXT("Direct3DCreate9") );
653 if( OurDirect3DCreate9 == NULL )
655 msg_Err( p_vout, "Cannot locate reference to Direct3DCreate9 ABI in DLL" );
659 /* Create the D3D object. */
660 p_d3dobj = OurDirect3DCreate9( D3D_SDK_VERSION );
661 if( NULL == p_d3dobj )
663 msg_Err( p_vout, "Could not create Direct3D9 instance.");
666 p_vout->p_sys->p_d3dobj = p_d3dobj;
669 ** Get device capabilities
671 ZeroMemory(&d3dCaps, sizeof(d3dCaps));
672 hr = IDirect3D9_GetDeviceCaps(p_d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps);
675 msg_Err( p_vout, "Could not read adapter capabilities. (hr=0x%lX)", hr);
678 /* TODO: need to test device capabilities and select the right render function */
683 /*****************************************************************************
684 * DirectD3DVoutRelease: release an instance of Direct3D9
685 *****************************************************************************/
687 static void Direct3DVoutRelease( vout_thread_t *p_vout )
689 if( p_vout->p_sys->p_d3dobj )
691 IDirect3D9_Release(p_vout->p_sys->p_d3dobj);
692 p_vout->p_sys->p_d3dobj = NULL;
694 if( NULL != p_vout->p_sys->hd3d9_dll )
696 FreeLibrary(p_vout->p_sys->hd3d9_dll);
697 p_vout->p_sys->hd3d9_dll = NULL;
701 /*****************************************************************************
702 * DirectD3DVoutOpen: Takes care of all the Direct3D9 initialisations
703 *****************************************************************************
704 * This function creates Direct3D device
705 * this must be called from the vout thread for performance reason, as
706 * all Direct3D Device APIs are used in a non multithread safe environment
707 *****************************************************************************/
708 static int Direct3DVoutOpen( vout_thread_t *p_vout )
711 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;;
712 D3DDISPLAYMODE d3ddm;
713 LPDIRECT3DDEVICE9 p_d3ddev;
716 ** Get the current desktop display mode, so we can set up a back
717 ** buffer of the same format
719 hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
722 msg_Err( p_vout, "Could not read adapter display mode. (hr=0x%lX)", hr);
726 /* Set up the structure used to create the D3DDevice. */
727 ZeroMemory( &p_vout->p_sys->d3dpp, sizeof(D3DPRESENT_PARAMETERS) );
728 p_vout->p_sys->d3dpp.Windowed = TRUE;
729 p_vout->p_sys->d3dpp.hDeviceWindow = p_vout->p_sys->hvideownd;
730 p_vout->p_sys->d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
731 p_vout->p_sys->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
732 p_vout->p_sys->d3dpp.BackBufferFormat = d3ddm.Format;
733 p_vout->p_sys->d3dpp.BackBufferCount = 1;
734 p_vout->p_sys->d3dpp.EnableAutoDepthStencil = TRUE;
735 p_vout->p_sys->d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
737 // Create the D3DDevice
738 hr = IDirect3D9_CreateDevice(p_d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL,
739 D3DCREATE_SOFTWARE_VERTEXPROCESSING, &(p_vout->p_sys->d3dpp), &p_d3ddev );
742 msg_Err(p_vout, "Could not create the D3D device! (hr=0x%lX)", hr);
745 p_vout->p_sys->p_d3ddev = p_d3ddev;
747 msg_Dbg( p_vout, "Direct3D device adapter successfully initialized" );
751 /*****************************************************************************
752 * DirectD3DClose: release the Direct3D9 device
753 *****************************************************************************/
754 static void Direct3DVoutClose( vout_thread_t *p_vout )
756 if( p_vout->p_sys->p_d3ddev )
758 IDirect3DDevice9_Release(p_vout->p_sys->p_d3ddev);
759 p_vout->p_sys->p_d3ddev = NULL;
762 p_vout->p_sys->hmonitor = NULL;
765 /*****************************************************************************
766 * DirectD3DClose: reset the Direct3D9 device
767 *****************************************************************************
768 * All resources must be deallocated before the reset occur, they will be
769 * realllocated once the reset has been performed successfully
770 *****************************************************************************/
771 static int Direct3DVoutResetDevice( vout_thread_t *p_vout, UINT i_width, UINT i_height )
773 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
774 D3DPRESENT_PARAMETERS d3dpp;
777 memcpy(&d3dpp, &(p_vout->p_sys->d3dpp), sizeof(d3dpp));
779 d3dpp.BackBufferWidth = i_width;
781 d3dpp.BackBufferHeight = i_height;
783 // release all D3D objects
784 Direct3DVoutReleaseScene( p_vout );
785 Direct3DVoutReleasePictures( p_vout );
787 hr = IDirect3DDevice9_Reset(p_d3ddev, &d3dpp);
791 if( (VLC_SUCCESS == Direct3DVoutCreatePictures(p_vout, 1))
792 && (VLC_SUCCESS == Direct3DVoutCreateScene(p_vout)) )
794 p_vout->p_sys->d3dpp.BackBufferWidth = i_width;
795 p_vout->p_sys->d3dpp.BackBufferHeight = i_height;
801 msg_Err(p_vout, "%s failed ! (hr=%08lX)", __FUNCTION__, hr);
807 static D3DFORMAT Direct3DVoutSelectFormat( vout_thread_t *p_vout, D3DFORMAT target,
808 const D3DFORMAT *formats, size_t count)
810 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
813 for( c=0; c<count; ++c )
816 D3DFORMAT format = formats[c];
817 hr = IDirect3D9_CheckDeviceFormatConversion(p_d3dobj,
818 D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
822 // found a compatible format
826 msg_Dbg( p_vout, "selected surface pixel format is UYVY");
829 msg_Dbg( p_vout, "selected surface pixel format is YUY2");
831 case D3DFMT_X8R8G8B8:
832 msg_Dbg( p_vout, "selected surface pixel format is X8R8G8B8");
834 case D3DFMT_A8R8G8B8:
835 msg_Dbg( p_vout, "selected surface pixel format is A8R8G8B8");
838 msg_Dbg( p_vout, "selected surface pixel format is R8G8B8");
841 msg_Dbg( p_vout, "selected surface pixel format is R5G6B5");
843 case D3DFMT_X1R5G5B5:
844 msg_Dbg( p_vout, "selected surface pixel format is X1R5G5B5");
847 msg_Dbg( p_vout, "selected surface pixel format is 0x%0X", format);
852 else if( D3DERR_NOTAVAILABLE != hr )
854 msg_Err( p_vout, "Could not query adapter supported formats. (hr=0x%lX)", hr);
858 return D3DFMT_UNKNOWN;
861 D3DFORMAT Direct3DVoutFindFormat(vout_thread_t *p_vout, int i_chroma, D3DFORMAT target)
863 if( p_vout->p_sys->b_hw_yuv )
867 case VLC_FOURCC('U','Y','V','Y'):
868 case VLC_FOURCC('U','Y','N','V'):
869 case VLC_FOURCC('Y','4','2','2'):
871 static const D3DFORMAT formats[] =
872 { D3DFMT_UYVY, D3DFMT_YUY2, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
873 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
875 case VLC_FOURCC('I','4','2','0'):
876 case VLC_FOURCC('I','4','2','2'):
877 case VLC_FOURCC('Y','V','1','2'):
879 /* typically 3D textures don't support planar format
880 ** fallback to packed version and use CPU for the conversion
882 static const D3DFORMAT formats[] =
883 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
884 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
886 case VLC_FOURCC('Y','U','Y','2'):
887 case VLC_FOURCC('Y','U','N','V'):
889 static const D3DFORMAT formats[] =
890 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
891 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
898 case VLC_FOURCC('R', 'V', '1', '5'):
900 static const D3DFORMAT formats[] =
902 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
904 case VLC_FOURCC('R', 'V', '1', '6'):
906 static const D3DFORMAT formats[] =
908 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
910 case VLC_FOURCC('R', 'V', '2', '4'):
912 static const D3DFORMAT formats[] =
913 { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
914 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
916 case VLC_FOURCC('R', 'V', '3', '2'):
918 static const D3DFORMAT formats[] =
919 { D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8 };
920 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
924 /* use display default format */
925 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
926 D3DDISPLAYMODE d3ddm;
928 HRESULT hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
932 ** some professional cards could use some advanced pixel format as default,
933 ** make sure we stick with chromas that we can handle internally
935 switch( d3ddm.Format )
938 case D3DFMT_X8R8G8B8:
939 case D3DFMT_A8R8G8B8:
940 msg_Dbg( p_vout, "defaulting to adpater pixel format");
941 return Direct3DVoutSelectFormat(p_vout, target, &d3ddm.Format, 1);
944 /* if we fall here, that probably means that we need to render some YUV format */
945 static const D3DFORMAT formats[] =
946 { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
947 msg_Dbg( p_vout, "defaulting to built-in pixel format");
948 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
954 return D3DFMT_UNKNOWN;
957 static int Direct3DVoutSetOutputFormat(vout_thread_t *p_vout, D3DFORMAT format)
962 p_vout->output.i_chroma = VLC_FOURCC('Y', 'U', 'Y', '2');
965 p_vout->output.i_chroma = VLC_FOURCC('U', 'Y', 'V', 'Y');
968 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '2', '4');
970 case D3DFMT_X8R8G8B8:
971 case D3DFMT_A8R8G8B8:
972 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '3', '2');
973 p_vout->output.i_rmask = 0x00ff0000;
974 p_vout->output.i_gmask = 0x0000ff00;
975 p_vout->output.i_bmask = 0x000000ff;
976 # if defined( WORDS_BIGENDIAN )
977 p_vout->output.i_rrshift = 0;
978 p_vout->output.i_lrshift = 24;
979 p_vout->output.i_rgshift = 0;
980 p_vout->output.i_lgshift = 16;
981 p_vout->output.i_rbshift = 0;
982 p_vout->output.i_lbshift = 8;
984 p_vout->output.i_rrshift = 0;
985 p_vout->output.i_lrshift = 8;
986 p_vout->output.i_rgshift = 0;
987 p_vout->output.i_lgshift = 16;
988 p_vout->output.i_rbshift = 0;
989 p_vout->output.i_lbshift = 24;
993 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '6');
994 p_vout->output.i_rmask = (0x1fL)<<11;
995 p_vout->output.i_gmask = (0x3fL)<<5;
996 p_vout->output.i_bmask = (0x1fL)<<0;
997 # if defined( WORDS_BIGENDIAN )
998 p_vout->output.i_rrshift = 0;
999 p_vout->output.i_lrshift = 11;
1000 p_vout->output.i_rgshift = 0;
1001 p_vout->output.i_lgshift = 5;
1002 p_vout->output.i_rbshift = 0;
1003 p_vout->output.i_lbshift = 0;
1005 /* FIXME: since components are not byte aligned,
1006 there is not chance that this will work */
1007 p_vout->output.i_rrshift = 0;
1008 p_vout->output.i_lrshift = 0;
1009 p_vout->output.i_rgshift = 0;
1010 p_vout->output.i_lgshift = 5;
1011 p_vout->output.i_rbshift = 0;
1012 p_vout->output.i_lbshift = 11;
1015 case D3DFMT_X1R5G5B5:
1016 p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '5');
1017 p_vout->output.i_rmask = (0x1fL)<<10;
1018 p_vout->output.i_gmask = (0x1fL)<<5;
1019 p_vout->output.i_bmask = (0x1fL)<<0;
1020 # if defined( WORDS_BIGENDIAN )
1021 p_vout->output.i_rrshift = 0;
1022 p_vout->output.i_lrshift = 10;
1023 p_vout->output.i_rgshift = 0;
1024 p_vout->output.i_lgshift = 5;
1025 p_vout->output.i_rbshift = 0;
1026 p_vout->output.i_lbshift = 0;
1028 /* FIXME: since components are not byte aligned,
1029 there is not chance that this will work */
1030 p_vout->output.i_rrshift = 0;
1031 p_vout->output.i_lrshift = 1;
1032 p_vout->output.i_rgshift = 0;
1033 p_vout->output.i_lgshift = 5;
1034 p_vout->output.i_rbshift = 0;
1035 p_vout->output.i_lbshift = 11;
1039 return VLC_EGENERIC;
1044 /*****************************************************************************
1045 * Direct3DVoutCreatePictures: allocate a vector of identical pictures
1046 *****************************************************************************
1047 * Each picture has an associated offscreen surface in video memory
1048 * depending on hardware capabilities the picture chroma will be as close
1049 * as possible to the orginal render chroma to reduce CPU conversion overhead
1050 * and delegate this work to video card GPU
1051 *****************************************************************************/
1052 static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics )
1054 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1055 D3DFORMAT format = p_vout->p_sys->d3dpp.BackBufferFormat;
1059 I_OUTPUTPICTURES = 0;
1062 ** find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
1063 ** the requested chroma which is usable by the hardware in an offscreen surface, as they
1064 ** typically support more formats than textures
1066 format = Direct3DVoutFindFormat(p_vout, p_vout->render.i_chroma, format);
1067 if( VLC_SUCCESS != Direct3DVoutSetOutputFormat(p_vout, format) )
1069 msg_Err(p_vout, "surface pixel format is not supported.");
1070 return VLC_EGENERIC;
1073 for( c=0; c<i_num_pics; )
1076 LPDIRECT3DSURFACE9 p_d3dsurf;
1077 picture_t *p_pic = p_vout->p_picture+c;
1079 hr = IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3ddev,
1080 p_vout->render.i_width,
1081 p_vout->render.i_height,
1088 msg_Err(p_vout, "Failed to create picture surface. (hr=0x%lx)", hr);
1089 Direct3DVoutReleasePictures(p_vout);
1090 return VLC_EGENERIC;
1093 /* fill surface with black color */
1094 IDirect3DDevice9_ColorFill(p_d3ddev, p_d3dsurf, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
1096 /* assign surface to internal structure */
1097 p_pic->p_sys = (void *)p_d3dsurf;
1099 /* Now that we've got our direct-buffer, we can finish filling in the
1100 * picture_t structures */
1101 switch( p_vout->output.i_chroma )
1103 case VLC_FOURCC('R','G','B','2'):
1104 p_pic->p->i_lines = p_vout->output.i_height;
1105 p_pic->p->i_visible_lines = p_vout->output.i_height;
1106 p_pic->p->i_pixel_pitch = 1;
1107 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1108 p_pic->p->i_pixel_pitch;
1109 p_pic->i_planes = 1;
1111 case VLC_FOURCC('R','V','1','5'):
1112 case VLC_FOURCC('R','V','1','6'):
1113 p_pic->p->i_lines = p_vout->output.i_height;
1114 p_pic->p->i_visible_lines = p_vout->output.i_height;
1115 p_pic->p->i_pixel_pitch = 2;
1116 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1117 p_pic->p->i_pixel_pitch;
1118 p_pic->i_planes = 1;
1120 case VLC_FOURCC('R','V','2','4'):
1121 p_pic->p->i_lines = p_vout->output.i_height;
1122 p_pic->p->i_visible_lines = p_vout->output.i_height;
1123 p_pic->p->i_pixel_pitch = 3;
1124 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1125 p_pic->p->i_pixel_pitch;
1126 p_pic->i_planes = 1;
1128 case VLC_FOURCC('R','V','3','2'):
1129 p_pic->p->i_lines = p_vout->output.i_height;
1130 p_pic->p->i_visible_lines = p_vout->output.i_height;
1131 p_pic->p->i_pixel_pitch = 4;
1132 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1133 p_pic->p->i_pixel_pitch;
1134 p_pic->i_planes = 1;
1136 case VLC_FOURCC('U','Y','V','Y'):
1137 case VLC_FOURCC('Y','U','Y','2'):
1138 p_pic->p->i_lines = p_vout->output.i_height;
1139 p_pic->p->i_visible_lines = p_vout->output.i_height;
1140 p_pic->p->i_pixel_pitch = 2;
1141 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1142 p_pic->p->i_pixel_pitch;
1143 p_pic->i_planes = 1;
1146 Direct3DVoutReleasePictures(p_vout);
1147 return VLC_EGENERIC;
1149 p_pic->i_status = DESTROYED_PICTURE;
1150 p_pic->i_type = DIRECT_PICTURE;
1151 p_pic->b_slow = VLC_TRUE;
1152 p_pic->pf_lock = Direct3DVoutLockSurface;
1153 p_pic->pf_unlock = Direct3DVoutUnlockSurface;
1154 PP_OUTPUTPICTURE[c] = p_pic;
1156 I_OUTPUTPICTURES = ++c;
1159 msg_Dbg( p_vout, "%u Direct3D pictures created successfully", c );
1164 /*****************************************************************************
1165 * Direct3DVoutReleasePictures: destroy a picture vector
1166 *****************************************************************************
1167 * release all video resources used for pictures
1168 *****************************************************************************/
1169 static void Direct3DVoutReleasePictures( vout_thread_t *p_vout)
1171 size_t i_num_pics = I_OUTPUTPICTURES;
1173 for( c=0; c<i_num_pics; ++c )
1175 picture_t *p_pic = p_vout->p_picture+c;
1178 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1180 p_pic->p_sys = NULL;
1184 IDirect3DSurface9_Release(p_d3dsurf);
1188 msg_Dbg( p_vout, "%u Direct3D pictures released.", c);
1190 I_OUTPUTPICTURES = 0;
1193 /*****************************************************************************
1194 * Direct3DVoutLockSurface: Lock surface and get picture data pointer
1195 *****************************************************************************
1196 * This function locks a surface and get the surface descriptor which amongst
1197 * other things has the pointer to the picture data.
1198 *****************************************************************************/
1199 static int Direct3DVoutLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1202 D3DLOCKED_RECT d3drect;
1203 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1205 if( NULL == p_d3dsurf )
1206 return VLC_EGENERIC;
1208 /* Lock the surface to get a valid pointer to the picture buffer */
1209 hr = IDirect3DSurface9_LockRect(p_d3dsurf, &d3drect, NULL, D3DLOCK_DISCARD);
1212 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1213 return VLC_EGENERIC;
1216 /* fill in buffer info in first plane */
1217 p_pic->p->p_pixels = d3drect.pBits;
1218 p_pic->p->i_pitch = d3drect.Pitch;
1223 /*****************************************************************************
1224 * Direct3DVoutUnlockSurface: Unlock a surface locked by Direct3DLockSurface().
1225 *****************************************************************************/
1226 static int Direct3DVoutUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1229 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1231 if( NULL == p_d3dsurf )
1232 return VLC_EGENERIC;
1234 /* Unlock the Surface */
1235 hr = IDirect3DSurface9_UnlockRect(p_d3dsurf);
1238 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1239 return VLC_EGENERIC;
1244 /*****************************************************************************
1245 * Direct3DVoutCreateScene: allocate and initialize a 3D scene
1246 *****************************************************************************
1247 * for advanced blending/filtering a texture needs be used in a 3D scene.
1248 *****************************************************************************/
1250 static int Direct3DVoutCreateScene( vout_thread_t *p_vout )
1252 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1253 LPDIRECT3DTEXTURE9 p_d3dtex;
1254 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
1259 ** Create a texture for use when rendering a scene
1260 ** for performance reason, texture format is identical to backbuffer
1261 ** which would usually be a RGB format
1263 hr = IDirect3DDevice9_CreateTexture(p_d3ddev,
1264 p_vout->render.i_width,
1265 p_vout->render.i_height,
1267 D3DUSAGE_RENDERTARGET,
1268 p_vout->p_sys->d3dpp.BackBufferFormat,
1274 msg_Err(p_vout, "Failed to create texture. (hr=0x%lx)", hr);
1275 return VLC_EGENERIC;
1279 ** Create a vertex buffer for use when rendering scene
1281 hr = IDirect3DDevice9_CreateVertexBuffer(p_d3ddev,
1282 sizeof(CUSTOMVERTEX)*4,
1284 D3DFVF_CUSTOMVERTEX,
1290 msg_Err(p_vout, "Failed to create vertex buffer. (hr=0x%lx)", hr);
1291 IDirect3DTexture9_Release(p_d3dtex);
1292 return VLC_EGENERIC;
1295 p_vout->p_sys->p_d3dtex = p_d3dtex;
1296 p_vout->p_sys->p_d3dvtc = p_d3dvtc;
1298 // Texture coordinates outside the range [0.0, 1.0] are set
1299 // to the texture color at 0.0 or 1.0, respectively.
1300 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1301 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1303 // Set linear filtering quality
1304 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
1305 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
1307 // set maximum ambient light
1308 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
1311 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_CULLMODE, D3DCULL_NONE);
1313 // Turn off the zbuffer
1314 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ZENABLE, D3DZB_FALSE);
1317 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_LIGHTING, FALSE);
1320 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DITHERENABLE, TRUE);
1323 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_STENCILENABLE, FALSE);
1326 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
1327 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
1328 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
1329 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHATESTENABLE,TRUE);
1330 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAREF, 0x10);
1331 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER);
1333 // Set texture states
1334 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE);
1335 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
1336 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
1338 // turn off alpha operation
1339 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
1341 msg_Dbg( p_vout, "Direct3D scene created successfully");
1346 /*****************************************************************************
1347 * Direct3DVoutReleaseScene
1348 *****************************************************************************/
1349 static void Direct3DVoutReleaseScene( vout_thread_t *p_vout )
1351 LPDIRECT3DTEXTURE9 p_d3dtex = p_vout->p_sys->p_d3dtex;
1352 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1356 IDirect3DVertexBuffer9_Release(p_d3dvtc);
1357 p_vout->p_sys->p_d3dvtc = NULL;
1362 IDirect3DTexture9_Release(p_d3dtex);
1363 p_vout->p_sys->p_d3dtex = NULL;
1365 msg_Dbg( p_vout, "Direct3D scene released successfully");
1368 /*****************************************************************************
1369 * Direct3DVoutRenderDefault: copy picture surface to display back buffer
1370 *****************************************************************************
1371 * This function is intented for lower end video cards, without pixel shader
1372 * support or low video RAM
1373 *****************************************************************************/
1374 static void Direct3DVoutRenderSurface( vout_thread_t *p_vout, picture_t *p_pic )
1376 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1377 LPDIRECT3DSURFACE9 p_d3dsrc, p_d3ddest;
1378 UINT iSwapChain, iSwapChains;
1381 // check if device is still available
1382 hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
1385 if( (D3DERR_DEVICENOTRESET != hr)
1386 || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, 0, 0)) )
1388 // device is not usable at present (lost device, out of video mem ?)
1393 /* retrieve the number of swap chains */
1394 iSwapChains = IDirect3DDevice9_GetNumberOfSwapChains(p_d3ddev);
1395 if( 0 == iSwapChains )
1397 msg_Dbg( p_vout, "no swap chain to render ?");
1401 /* retrieve picture surface */
1402 p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1403 if( NULL == p_d3dsrc )
1405 msg_Dbg( p_vout, "no surface to render ?");
1409 for( iSwapChain=0; iSwapChain < iSwapChains; ++iSwapChain )
1411 /* retrieve swap chain back buffer */
1412 hr = IDirect3DDevice9_GetBackBuffer(p_d3ddev, iSwapChain, 0, D3DBACKBUFFER_TYPE_MONO, &p_d3ddest);
1415 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1419 /* Copy picture surface into back buffer surface, color space conversion happens here */
1420 hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, NULL, p_d3ddest, NULL, D3DTEXF_NONE);
1421 IDirect3DSurface9_Release(p_d3ddest);
1424 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1430 /*****************************************************************************
1431 * Render: copy picture surface into a texture and render into a scene
1432 *****************************************************************************
1433 * This function is intented for higher end 3D cards, with pixel shader support
1434 * and at least 64 MB of video RAM.
1435 *****************************************************************************/
1436 static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic )
1438 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1439 LPDIRECT3DTEXTURE9 p_d3dtex = p_vout->p_sys->p_d3dtex;
1440 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1441 LPDIRECT3DSURFACE9 p_d3dsrc, p_d3ddest;
1442 CUSTOMVERTEX *p_vertices;
1444 float f_width, f_height;
1446 // check if device is still available
1447 hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
1450 if( (D3DERR_DEVICENOTRESET != hr)
1451 || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, 0, 0)) )
1453 // device is not usable at present (lost device, out of video mem ?)
1458 /* Clear the backbuffer and the zbuffer */
1459 hr = IDirect3DDevice9_Clear( p_d3ddev, 0, NULL, D3DCLEAR_TARGET,
1460 D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0 );
1463 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1467 /* retrieve picture surface */
1468 p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1469 if( NULL == p_d3dsrc )
1471 msg_Dbg( p_vout, "no surface to render ?");
1475 /* retrieve texture top-level surface */
1476 hr = IDirect3DTexture9_GetSurfaceLevel(p_d3dtex, 0, &p_d3ddest);
1479 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1483 /* Copy picture surface into texture surface, color space conversion happens here */
1484 hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, NULL, p_d3ddest, NULL, D3DTEXF_NONE);
1485 IDirect3DSurface9_Release(p_d3ddest);
1488 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1492 /* Update the vertex buffer */
1493 hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (VOID **)(&p_vertices), D3DLOCK_DISCARD);
1496 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1500 /* Setup vertices */
1501 f_width = (float)(p_vout->p_sys->d3dpp.BackBufferWidth);
1502 f_height = (float)(p_vout->p_sys->d3dpp.BackBufferHeight);
1504 p_vertices[0].x = 0.0f; // left
1505 p_vertices[0].y = 0.0f; // top
1506 p_vertices[0].z = 0.0f;
1507 p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1508 p_vertices[0].rhw = 1.0f;
1509 p_vertices[0].tu = 0.0f;
1510 p_vertices[0].tv = 0.0f;
1512 p_vertices[1].x = f_width; // right
1513 p_vertices[1].y = 0.0f; // top
1514 p_vertices[1].z = 0.0f;
1515 p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1516 p_vertices[1].rhw = 1.0f;
1517 p_vertices[1].tu = 1.0f;
1518 p_vertices[1].tv = 0.0f;
1520 p_vertices[2].x = f_width; // right
1521 p_vertices[2].y = f_height; // bottom
1522 p_vertices[2].z = 0.0f;
1523 p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1524 p_vertices[2].rhw = 1.0f;
1525 p_vertices[2].tu = 1.0f;
1526 p_vertices[2].tv = 1.0f;
1528 p_vertices[3].x = 0.0f; // left
1529 p_vertices[3].y = f_height; // bottom
1530 p_vertices[3].z = 0.0f;
1531 p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1532 p_vertices[3].rhw = 1.0f;
1533 p_vertices[3].tu = 0.0f;
1534 p_vertices[3].tv = 1.0f;
1536 hr= IDirect3DVertexBuffer9_Unlock(p_d3dvtc);
1539 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1544 hr = IDirect3DDevice9_BeginScene(p_d3ddev);
1547 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1551 // Setup our texture. Using textures introduces the texture stage states,
1552 // which govern how textures get blended together (in the case of multiple
1553 // textures) and lighting information. In this case, we are modulating
1554 // (blending) our texture with the diffuse color of the vertices.
1555 hr = IDirect3DDevice9_SetTexture(p_d3ddev, 0, (LPDIRECT3DBASETEXTURE9)p_d3dtex);
1558 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1559 IDirect3DDevice9_EndScene(p_d3ddev);
1563 // Render the vertex buffer contents
1564 hr = IDirect3DDevice9_SetStreamSource(p_d3ddev, 0, p_d3dvtc, 0, sizeof(CUSTOMVERTEX));
1567 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1568 IDirect3DDevice9_EndScene(p_d3ddev);
1572 // we use FVF instead of vertex shader
1573 hr = IDirect3DDevice9_SetVertexShader(p_d3ddev, NULL);
1576 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1577 IDirect3DDevice9_EndScene(p_d3ddev);
1581 hr = IDirect3DDevice9_SetFVF(p_d3ddev, D3DFVF_CUSTOMVERTEX);
1584 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1585 IDirect3DDevice9_EndScene(p_d3ddev);
1590 hr = IDirect3DDevice9_DrawPrimitive(p_d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
1593 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1594 IDirect3DDevice9_EndScene(p_d3ddev);
1599 hr = IDirect3DDevice9_EndScene(p_d3ddev);
1602 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);