1 /*****************************************************************************
2 * direct3d.c: Windows Direct3D video output module
3 *****************************************************************************
4 * Copyright (C) 2006-2009 the VideoLAN team
7 * Authors: Damien Fouilleul <damienf@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
27 * This plugin will use YUV surface if supported, using YUV will result in
28 * the best video quality (hardware filering when rescaling the picture)
29 * and the fastest display as it requires less processing.
31 * If YUV overlay is not supported this plugin will use RGB offscreen video
32 * surfaces that will be blitted onto the primary surface (display) to
33 * effectively display the pictures.
35 *****************************************************************************/
36 #include <errno.h> /* ENOMEM */
42 #include <vlc_common.h>
43 #include <vlc_plugin.h>
44 #include <vlc_interface.h>
45 #include <vlc_playlist.h>
53 /*****************************************************************************
55 *****************************************************************************/
56 static int OpenVideo ( vlc_object_t
* );
57 static void CloseVideo ( vlc_object_t
* );
59 static int Init ( vout_thread_t
* );
60 static void End ( vout_thread_t
* );
61 static int Manage ( vout_thread_t
* );
62 static void Display ( vout_thread_t
*, picture_t
* );
63 static void FirstDisplay( vout_thread_t
*, picture_t
* );
65 static int Direct3DVoutCreate ( vout_thread_t
* );
66 static void Direct3DVoutRelease ( vout_thread_t
* );
68 static int Direct3DVoutOpen ( vout_thread_t
* );
69 static void Direct3DVoutClose ( vout_thread_t
* );
71 static int Direct3DVoutResetDevice( vout_thread_t
* );
73 static int Direct3DVoutCreatePictures ( vout_thread_t
*, size_t );
74 static void Direct3DVoutReleasePictures ( vout_thread_t
* );
76 static int Direct3DVoutLockSurface ( vout_thread_t
*, picture_t
* );
77 static int Direct3DVoutUnlockSurface( vout_thread_t
*, picture_t
* );
79 static int Direct3DVoutCreateScene ( vout_thread_t
* );
80 static void Direct3DVoutReleaseScene ( vout_thread_t
* );
81 static void Direct3DVoutRenderScene ( vout_thread_t
*, picture_t
* );
83 static int DesktopCallback( vlc_object_t
*p_this
, char const *psz_cmd
,
84 vlc_value_t oldval
, vlc_value_t newval
,
87 /*****************************************************************************
89 *****************************************************************************/
91 static bool IsVistaOrAbove(void)
94 winVer
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
96 if( GetVersionEx(&winVer
) )
98 if( winVer
.dwMajorVersion
> 5 )
100 /* Windows Vista or above, make this module the default */
104 /* Windows XP or lower, make sure this module isn't the default */
108 static int OpenVideoXP( vlc_object_t
*obj
)
110 return IsVistaOrAbove() ? VLC_EGENERIC
: OpenVideo( obj
);
113 static int OpenVideoVista( vlc_object_t
*obj
)
115 return IsVistaOrAbove() ? OpenVideo( obj
) : VLC_EGENERIC
;
118 #define DESKTOP_TEXT N_("Enable desktop mode ")
119 #define DESKTOP_LONGTEXT N_( \
120 "The desktop mode allows you to display the video on the desktop." )
123 set_shortname( "Direct3D" )
124 set_category( CAT_VIDEO
)
125 set_subcategory( SUBCAT_VIDEO_VOUT
)
127 add_bool( "direct3d-desktop", 0, NULL
, DESKTOP_TEXT
, DESKTOP_LONGTEXT
,
130 set_description( N_("DirectX 3D video output") )
131 set_capability( "video output", 50 )
132 add_shortcut( "direct3d" )
133 set_callbacks( OpenVideoXP
, CloseVideo
)
135 /* FIXME: Hack to avoid unregistering our window class */
136 linked_with_a_crap_library_which_uses_atexit ()
139 set_capability( "video output", 150 )
140 add_shortcut( "direct3d" )
141 set_callbacks( OpenVideoVista
, CloseVideo
)
145 /* check if we registered a window class because we need to
148 if( GetClassInfo( GetModuleHandle(NULL
), "VLC DirectX", &wndclass
) )
149 UnregisterClass( "VLC DirectX", GetModuleHandle(NULL
) );
152 /*****************************************************************************
154 *****************************************************************************
155 *****************************************************************************/
158 FLOAT x
,y
,z
; // vertex untransformed position
159 FLOAT rhw
; // eye distance
160 D3DCOLOR diffuse
; // diffuse color
161 FLOAT tu
, tv
; // texture relative coordinates
164 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
166 /*****************************************************************************
167 * OpenVideo: allocate Vout video thread output method
168 *****************************************************************************
169 * This function allocates and initialize the Direct3D vout method.
170 *****************************************************************************/
171 static int OpenVideo( vlc_object_t
*p_this
)
174 vout_thread_t
* p_vout
= (vout_thread_t
*)p_this
;
176 /* Allocate structure */
177 p_vout
->p_sys
= calloc( 1, sizeof( vout_sys_t
) );
178 if( p_vout
->p_sys
== NULL
)
181 if( VLC_SUCCESS
!= Direct3DVoutCreate( p_vout
) )
183 msg_Err( p_vout
, "Direct3D could not be initialized !");
184 Direct3DVoutRelease( p_vout
);
185 free( p_vout
->p_sys
);
189 /* Initialisations */
190 p_vout
->pf_init
= Init
;
191 p_vout
->pf_end
= End
;
192 p_vout
->pf_manage
= Manage
;
193 p_vout
->pf_render
= Direct3DVoutRenderScene
;
194 p_vout
->pf_display
= FirstDisplay
;
196 p_vout
->p_sys
->hwnd
= p_vout
->p_sys
->hvideownd
= NULL
;
197 p_vout
->p_sys
->hparent
= p_vout
->p_sys
->hfswnd
= NULL
;
198 p_vout
->p_sys
->i_changes
= 0;
199 p_vout
->p_sys
->b_desktop
= false;
200 vlc_mutex_init( &p_vout
->p_sys
->lock
);
201 SetRectEmpty( &p_vout
->p_sys
->rect_display
);
202 SetRectEmpty( &p_vout
->p_sys
->rect_parent
);
204 var_Create( p_vout
, "directx-hw-yuv", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
205 var_Create( p_vout
, "directx-device", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
207 p_vout
->p_sys
->b_cursor_hidden
= 0;
208 p_vout
->p_sys
->i_lastmoved
= mdate();
209 p_vout
->p_sys
->i_mouse_hide_timeout
=
210 var_GetInteger(p_vout
, "mouse-hide-timeout") * 1000;
212 var_Create( p_vout
, "video-title", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
213 var_Create( p_vout
, "disable-screensaver", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
215 /* Set main window's size */
216 p_vout
->p_sys
->i_window_width
= p_vout
->i_window_width
;
217 p_vout
->p_sys
->i_window_height
= p_vout
->i_window_height
;
219 if ( CreateEventThread( p_vout
) )
221 /* Variable to indicate if the window should be on top of others */
222 /* Trigger a callback right now */
223 var_TriggerCallback( p_vout
, "video-on-top" );
225 /* Trigger a callback right now */
226 var_Create( p_vout
, "direct3d-desktop", VLC_VAR_BOOL
|VLC_VAR_DOINHERIT
);
227 val
.psz_string
= _("Desktop");
228 var_Change( p_vout
, "direct3d-desktop", VLC_VAR_SETTEXT
, &val
, NULL
);
229 var_AddCallback( p_vout
, "direct3d-desktop", DesktopCallback
, NULL
);
230 var_TriggerCallback( p_vout
, "direct3d-desktop" );
232 DisableScreensaver ( p_vout
);
238 CloseVideo( VLC_OBJECT(p_vout
) );
243 /*****************************************************************************
244 * CloseVideo: destroy Sys video thread output method
245 *****************************************************************************
246 * Terminate an output method created by Create
247 *****************************************************************************/
248 static void CloseVideo( vlc_object_t
*p_this
)
250 vout_thread_t
* p_vout
= (vout_thread_t
*)p_this
;
252 Direct3DVoutRelease( p_vout
);
254 StopEventThread( p_vout
);
256 RestoreScreensaver( p_vout
);
258 free( p_vout
->p_sys
);
259 p_vout
->p_sys
= NULL
;
262 /*****************************************************************************
263 * Init: initialize Direct3D video thread output method
264 *****************************************************************************/
265 static int Init( vout_thread_t
*p_vout
)
269 p_vout
->p_sys
->b_hw_yuv
= var_GetBool( p_vout
, "directx-hw-yuv" );
271 /* Initialise Direct3D */
272 if( VLC_SUCCESS
!= Direct3DVoutOpen( p_vout
) )
274 msg_Err( p_vout
, "cannot initialize Direct3D" );
278 /* Initialize the output structure.
279 * Since Direct3D can do rescaling for us, stick to the default
280 * coordinates and aspect. */
281 p_vout
->output
.i_width
= p_vout
->render
.i_width
;
282 p_vout
->output
.i_height
= p_vout
->render
.i_height
;
283 p_vout
->output
.i_aspect
= p_vout
->render
.i_aspect
;
284 p_vout
->fmt_out
= p_vout
->fmt_in
;
285 UpdateRects( p_vout
, true );
287 /* create picture pool */
288 p_vout
->output
.i_chroma
= 0;
289 i_ret
= Direct3DVoutCreatePictures(p_vout
, 1);
290 if( VLC_SUCCESS
!= i_ret
)
292 msg_Err(p_vout
, "Direct3D picture pool initialization failed !");
297 i_ret
= Direct3DVoutCreateScene(p_vout
);
298 if( VLC_SUCCESS
!= i_ret
)
300 msg_Err(p_vout
, "Direct3D scene initialization failed !");
301 Direct3DVoutReleasePictures(p_vout
);
305 /* Change the window title bar text */
306 PostMessage( p_vout
->p_sys
->hwnd
, WM_VLC_CHANGE_TEXT
, 0, 0 );
308 p_vout
->fmt_out
.i_chroma
= p_vout
->output
.i_chroma
;
312 /*****************************************************************************
313 * End: terminate Sys video thread output method
314 *****************************************************************************
315 * Terminate an output method created by Create.
316 * It is called at the end of the thread.
317 *****************************************************************************/
318 static void End( vout_thread_t
*p_vout
)
320 Direct3DVoutReleaseScene(p_vout
);
321 Direct3DVoutReleasePictures(p_vout
);
322 Direct3DVoutClose( p_vout
);
325 /*****************************************************************************
326 * Manage: handle Sys events
327 *****************************************************************************
328 * This function should be called regularly by the video output thread.
329 * It returns a non null value if an error occurred.
330 *****************************************************************************/
331 static int Manage( vout_thread_t
*p_vout
)
333 /* If we do not control our window, we check for geometry changes
334 * ourselves because the parent might not send us its events. */
335 vlc_mutex_lock( &p_vout
->p_sys
->lock
);
336 if( p_vout
->p_sys
->hparent
&& !p_vout
->b_fullscreen
)
341 vlc_mutex_unlock( &p_vout
->p_sys
->lock
);
343 GetClientRect( p_vout
->p_sys
->hparent
, &rect_parent
);
344 point
.x
= point
.y
= 0;
345 ClientToScreen( p_vout
->p_sys
->hparent
, &point
);
346 OffsetRect( &rect_parent
, point
.x
, point
.y
);
348 if( !EqualRect( &rect_parent
, &p_vout
->p_sys
->rect_parent
) )
350 p_vout
->p_sys
->rect_parent
= rect_parent
;
352 SetWindowPos( p_vout
->p_sys
->hwnd
, 0, 0, 0,
353 rect_parent
.right
- rect_parent
.left
,
354 rect_parent
.bottom
- rect_parent
.top
,
356 UpdateRects( p_vout
, true );
361 vlc_mutex_unlock( &p_vout
->p_sys
->lock
);
367 if( p_vout
->p_sys
->i_changes
& DX_POSITION_CHANGE
)
369 #if 0 /* need that when bicubic filter is available */
373 GetClientRect(p_vout
->p_sys
->hvideownd
, &rect
);
374 width
= rect
.right
-rect
.left
;
375 height
= rect
.bottom
-rect
.top
;
377 if( (width
!= p_vout
->p_sys
->d3dpp
.BackBufferWidth
)
378 || (height
!= p_vout
->p_sys
->d3dpp
.BackBufferHeight
) )
380 msg_Dbg(p_vout
, "resizing device back buffers to (%lux%lu)", width
, height
);
381 // need to reset D3D device to resize back buffer
382 if( VLC_SUCCESS
!= Direct3DVoutResetDevice(p_vout
, width
, height
) )
386 p_vout
->p_sys
->i_changes
&= ~DX_POSITION_CHANGE
;
390 * Desktop mode change
392 if( p_vout
->p_sys
->i_changes
& DX_DESKTOP_CHANGE
)
394 /* Close the direct3d instance attached to the current output window. */
396 StopEventThread( p_vout
);
397 /* Set the switching mode flag */
398 p_vout
->p_sys
->i_changes
|= SWITCHING_MODE_FLAG
;
400 p_vout
->p_sys
->i_changes
&= ~DX_DESKTOP_CHANGE
;
403 if( p_vout
->p_sys
->i_changes
& EVENT_THREAD_ENDED
404 && p_vout
->p_sys
->i_changes
& SWITCHING_MODE_FLAG
)
406 /* Open the direct3d output and attaches it to the new window */
407 p_vout
->p_sys
->b_desktop
= !p_vout
->p_sys
->b_desktop
;
408 p_vout
->pf_display
= FirstDisplay
;
410 CreateEventThread( p_vout
);
413 /* Reset the flags */
414 p_vout
->p_sys
->i_changes
&= ~EVENT_THREAD_ENDED
;
415 p_vout
->p_sys
->i_changes
&= ~SWITCHING_MODE_FLAG
;
418 /* autoscale toggle */
419 if( p_vout
->i_changes
& VOUT_SCALE_CHANGE
)
421 p_vout
->i_changes
&= ~VOUT_SCALE_CHANGE
;
423 p_vout
->b_autoscale
= var_GetBool( p_vout
, "autoscale" );
424 p_vout
->i_zoom
= (int) ZOOM_FP_FACTOR
;
426 UpdateRects( p_vout
, true );
430 if( p_vout
->i_changes
& VOUT_ZOOM_CHANGE
)
432 p_vout
->i_changes
&= ~VOUT_ZOOM_CHANGE
;
434 p_vout
->b_autoscale
= false;
436 (int)( ZOOM_FP_FACTOR
* var_GetFloat( p_vout
, "scale" ) );
437 UpdateRects( p_vout
, true );
440 /* Check for cropping / aspect changes */
441 if( p_vout
->i_changes
& VOUT_CROP_CHANGE
||
442 p_vout
->i_changes
& VOUT_ASPECT_CHANGE
)
444 p_vout
->i_changes
&= ~VOUT_CROP_CHANGE
;
445 p_vout
->i_changes
&= ~VOUT_ASPECT_CHANGE
;
447 p_vout
->fmt_out
.i_x_offset
= p_vout
->fmt_in
.i_x_offset
;
448 p_vout
->fmt_out
.i_y_offset
= p_vout
->fmt_in
.i_y_offset
;
449 p_vout
->fmt_out
.i_visible_width
= p_vout
->fmt_in
.i_visible_width
;
450 p_vout
->fmt_out
.i_visible_height
= p_vout
->fmt_in
.i_visible_height
;
451 p_vout
->fmt_out
.i_aspect
= p_vout
->fmt_in
.i_aspect
;
452 p_vout
->fmt_out
.i_sar_num
= p_vout
->fmt_in
.i_sar_num
;
453 p_vout
->fmt_out
.i_sar_den
= p_vout
->fmt_in
.i_sar_den
;
454 p_vout
->output
.i_aspect
= p_vout
->fmt_in
.i_aspect
;
455 UpdateRects( p_vout
, true );
458 /* We used to call the Win32 PeekMessage function here to read the window
459 * messages. But since window can stay blocked into this function for a
460 * long time (for example when you move your window on the screen), I
461 * decided to isolate PeekMessage in another thread. */
466 if( p_vout
->i_changes
& VOUT_FULLSCREEN_CHANGE
467 || p_vout
->p_sys
->i_changes
& VOUT_FULLSCREEN_CHANGE
)
469 Win32ToggleFullscreen( p_vout
);
471 p_vout
->i_changes
&= ~VOUT_FULLSCREEN_CHANGE
;
472 p_vout
->p_sys
->i_changes
&= ~VOUT_FULLSCREEN_CHANGE
;
478 if( p_vout
->b_fullscreen
&& !p_vout
->p_sys
->b_cursor_hidden
&&
479 (mdate() - p_vout
->p_sys
->i_lastmoved
) >
480 p_vout
->p_sys
->i_mouse_hide_timeout
)
485 /* Hide the cursor only if it is inside our window */
486 GetCursorPos( &point
);
487 hwnd
= WindowFromPoint(point
);
488 if( hwnd
== p_vout
->p_sys
->hwnd
|| hwnd
== p_vout
->p_sys
->hvideownd
)
490 PostMessage( p_vout
->p_sys
->hwnd
, WM_VLC_HIDE_MOUSE
, 0, 0 );
494 p_vout
->p_sys
->i_lastmoved
= mdate();
499 * "Always on top" status change
501 if( p_vout
->p_sys
->b_on_top_change
)
503 HMENU hMenu
= GetSystemMenu( p_vout
->p_sys
->hwnd
, FALSE
);
504 bool b
= var_GetBool( p_vout
, "video-on-top" );
506 /* Set the window on top if necessary */
507 if( b
&& !( GetWindowLong( p_vout
->p_sys
->hwnd
, GWL_EXSTYLE
)
510 CheckMenuItem( hMenu
, IDM_TOGGLE_ON_TOP
,
511 MF_BYCOMMAND
| MFS_CHECKED
);
512 SetWindowPos( p_vout
->p_sys
->hwnd
, HWND_TOPMOST
, 0, 0, 0, 0,
513 SWP_NOSIZE
| SWP_NOMOVE
);
516 /* The window shouldn't be on top */
517 if( !b
&& ( GetWindowLong( p_vout
->p_sys
->hwnd
, GWL_EXSTYLE
)
520 CheckMenuItem( hMenu
, IDM_TOGGLE_ON_TOP
,
521 MF_BYCOMMAND
| MFS_UNCHECKED
);
522 SetWindowPos( p_vout
->p_sys
->hwnd
, HWND_NOTOPMOST
, 0, 0, 0, 0,
523 SWP_NOSIZE
| SWP_NOMOVE
);
526 p_vout
->p_sys
->b_on_top_change
= false;
529 /* Check if the event thread is still running */
530 if( !vlc_object_alive (p_vout
->p_sys
->p_event
) )
532 return VLC_EGENERIC
; /* exit */
538 /*****************************************************************************
539 * Display: displays previously rendered output
540 *****************************************************************************
541 * This function sends the currently rendered image to the display, wait until
542 * it is displayed and switch the two rendering buffers, preparing next frame.
543 *****************************************************************************/
544 static void Display( vout_thread_t
*p_vout
, picture_t
*p_pic
)
546 LPDIRECT3DDEVICE9 p_d3ddev
= p_vout
->p_sys
->p_d3ddev
;
548 if( p_vout
->p_sys
->i_changes
& SWITCHING_MODE_FLAG
)
551 // Present the back buffer contents to the display
552 // stretching and filtering happens here
553 HRESULT hr
= IDirect3DDevice9_Present(p_d3ddev
,
554 &(p_vout
->p_sys
->rect_src_clipped
),
557 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
561 ** this function is only used once when the first picture is received
562 ** this function will show the video window once a picture is ready
565 static void FirstDisplay( vout_thread_t
*p_vout
, picture_t
*p_pic
)
567 /* get initial picture presented through D3D */
568 Display(p_vout
, p_pic
);
571 ** Video window is initially hidden, show it now since we got a
574 SetWindowPos( p_vout
->p_sys
->hvideownd
, 0, 0, 0, 0, 0,
582 /* use and restores proper display function for further pictures */
583 p_vout
->pf_display
= Display
;
586 /*****************************************************************************
587 * DirectD3DVoutCreate: Initialize and instance of Direct3D9
588 *****************************************************************************
589 * This function initialize Direct3D and analyze available resources from
591 *****************************************************************************/
592 static int Direct3DVoutCreate( vout_thread_t
*p_vout
)
595 LPDIRECT3D9 p_d3dobj
;
598 LPDIRECT3D9 (WINAPI
*OurDirect3DCreate9
)(UINT SDKVersion
);
600 p_vout
->p_sys
->hd3d9_dll
= LoadLibrary(TEXT("D3D9.DLL"));
601 if( NULL
== p_vout
->p_sys
->hd3d9_dll
)
603 msg_Warn( p_vout
, "cannot load d3d9.dll, aborting" );
608 (void *)GetProcAddress( p_vout
->p_sys
->hd3d9_dll
,
609 TEXT("Direct3DCreate9") );
610 if( OurDirect3DCreate9
== NULL
)
612 msg_Err( p_vout
, "Cannot locate reference to Direct3DCreate9 ABI in DLL" );
616 /* Create the D3D object. */
617 p_d3dobj
= OurDirect3DCreate9( D3D_SDK_VERSION
);
618 if( NULL
== p_d3dobj
)
620 msg_Err( p_vout
, "Could not create Direct3D9 instance.");
623 p_vout
->p_sys
->p_d3dobj
= p_d3dobj
;
626 ** Get device capabilities
628 ZeroMemory(&d3dCaps
, sizeof(d3dCaps
));
629 hr
= IDirect3D9_GetDeviceCaps(p_d3dobj
, D3DADAPTER_DEFAULT
, D3DDEVTYPE_HAL
, &d3dCaps
);
632 msg_Err( p_vout
, "Could not read adapter capabilities. (hr=0x%lX)", hr
);
635 /* TODO: need to test device capabilities and select the right render function */
640 /*****************************************************************************
641 * DirectD3DVoutRelease: release an instance of Direct3D9
642 *****************************************************************************/
644 static void Direct3DVoutRelease( vout_thread_t
*p_vout
)
646 if( p_vout
->p_sys
->p_d3dobj
)
648 IDirect3D9_Release(p_vout
->p_sys
->p_d3dobj
);
649 p_vout
->p_sys
->p_d3dobj
= NULL
;
651 if( NULL
!= p_vout
->p_sys
->hd3d9_dll
)
653 FreeLibrary(p_vout
->p_sys
->hd3d9_dll
);
654 p_vout
->p_sys
->hd3d9_dll
= NULL
;
658 static int Direct3DFillPresentationParameters(vout_thread_t
*p_vout
, D3DPRESENT_PARAMETERS
*d3dpp
)
660 LPDIRECT3D9 p_d3dobj
= p_vout
->p_sys
->p_d3dobj
;
661 D3DDISPLAYMODE d3ddm
;
665 ** Get the current desktop display mode, so we can set up a back
666 ** buffer of the same format
668 hr
= IDirect3D9_GetAdapterDisplayMode(p_d3dobj
, D3DADAPTER_DEFAULT
, &d3ddm
);
671 msg_Err( p_vout
, "Could not read adapter display mode. (hr=0x%lX)", hr
);
675 /* keep a copy of current desktop format */
676 p_vout
->p_sys
->bbFormat
= d3ddm
.Format
;
678 /* Set up the structure used to create the D3DDevice. */
679 ZeroMemory( d3dpp
, sizeof(D3DPRESENT_PARAMETERS
) );
680 d3dpp
->Flags
= D3DPRESENTFLAG_VIDEO
;
681 d3dpp
->Windowed
= TRUE
;
682 d3dpp
->hDeviceWindow
= p_vout
->p_sys
->hvideownd
;
683 d3dpp
->BackBufferWidth
= p_vout
->output
.i_width
;
684 d3dpp
->BackBufferHeight
= p_vout
->output
.i_height
;
685 d3dpp
->SwapEffect
= D3DSWAPEFFECT_COPY
;
686 d3dpp
->MultiSampleType
= D3DMULTISAMPLE_NONE
;
687 d3dpp
->PresentationInterval
= D3DPRESENT_INTERVAL_DEFAULT
;
688 d3dpp
->BackBufferFormat
= d3ddm
.Format
;
689 d3dpp
->BackBufferCount
= 1;
690 d3dpp
->EnableAutoDepthStencil
= FALSE
;
695 /*****************************************************************************
696 * DirectD3DVoutOpen: Takes care of all the Direct3D9 initialisations
697 *****************************************************************************
698 * This function creates Direct3D device
699 * this must be called from the vout thread for performance reason, as
700 * all Direct3D Device APIs are used in a non multithread safe environment
701 *****************************************************************************/
702 static int Direct3DVoutOpen( vout_thread_t
*p_vout
)
704 LPDIRECT3D9 p_d3dobj
= p_vout
->p_sys
->p_d3dobj
;
705 LPDIRECT3DDEVICE9 p_d3ddev
;
706 D3DPRESENT_PARAMETERS d3dpp
;
709 if( VLC_SUCCESS
!= Direct3DFillPresentationParameters(p_vout
, &d3dpp
) )
712 // Create the D3DDevice
713 hr
= IDirect3D9_CreateDevice(p_d3dobj
, D3DADAPTER_DEFAULT
,
714 D3DDEVTYPE_HAL
, p_vout
->p_sys
->hvideownd
,
715 D3DCREATE_SOFTWARE_VERTEXPROCESSING
|
716 D3DCREATE_MULTITHREADED
,
720 msg_Err(p_vout
, "Could not create the D3D device! (hr=0x%lX)", hr
);
723 p_vout
->p_sys
->p_d3ddev
= p_d3ddev
;
725 msg_Dbg( p_vout
, "Direct3D device adapter successfully initialized" );
729 /*****************************************************************************
730 * DirectD3DClose: release the Direct3D9 device
731 *****************************************************************************/
732 static void Direct3DVoutClose( vout_thread_t
*p_vout
)
734 if( p_vout
->p_sys
->p_d3ddev
)
736 IDirect3DDevice9_Release(p_vout
->p_sys
->p_d3ddev
);
737 p_vout
->p_sys
->p_d3ddev
= NULL
;
740 p_vout
->p_sys
->hmonitor
= NULL
;
743 /*****************************************************************************
744 * DirectD3DClose: reset the Direct3D9 device
745 *****************************************************************************
746 * All resources must be deallocated before the reset occur, they will be
747 * realllocated once the reset has been performed successfully
748 *****************************************************************************/
749 static int Direct3DVoutResetDevice( vout_thread_t
*p_vout
)
751 LPDIRECT3DDEVICE9 p_d3ddev
= p_vout
->p_sys
->p_d3ddev
;
752 D3DPRESENT_PARAMETERS d3dpp
;
755 if( VLC_SUCCESS
!= Direct3DFillPresentationParameters(p_vout
, &d3dpp
) )
758 // release all D3D objects
759 Direct3DVoutReleaseScene( p_vout
);
760 Direct3DVoutReleasePictures( p_vout
);
762 hr
= IDirect3DDevice9_Reset(p_d3ddev
, &d3dpp
);
766 if( (VLC_SUCCESS
!= Direct3DVoutCreatePictures(p_vout
, 1))
767 || (VLC_SUCCESS
!= Direct3DVoutCreateScene(p_vout
)) )
769 msg_Dbg(p_vout
, "%s failed !", __FUNCTION__
);
774 msg_Err(p_vout
, "%s failed ! (hr=%08lX)", __FUNCTION__
, hr
);
780 static D3DFORMAT
Direct3DVoutSelectFormat( vout_thread_t
*p_vout
, D3DFORMAT target
,
781 const D3DFORMAT
*formats
, size_t count
)
783 LPDIRECT3D9 p_d3dobj
= p_vout
->p_sys
->p_d3dobj
;
786 for( c
=0; c
<count
; ++c
)
789 D3DFORMAT format
= formats
[c
];
790 /* test whether device can create a surface of that format */
791 hr
= IDirect3D9_CheckDeviceFormat(p_d3dobj
, D3DADAPTER_DEFAULT
,
792 D3DDEVTYPE_HAL
, target
, 0, D3DRTYPE_SURFACE
, format
);
795 /* test whether device can perform color-conversion
796 ** from that format to target format
798 hr
= IDirect3D9_CheckDeviceFormatConversion(p_d3dobj
,
799 D3DADAPTER_DEFAULT
, D3DDEVTYPE_HAL
,
804 // found a compatible format
808 msg_Dbg( p_vout
, "selected surface pixel format is UYVY");
811 msg_Dbg( p_vout
, "selected surface pixel format is YUY2");
813 case D3DFMT_X8R8G8B8
:
814 msg_Dbg( p_vout
, "selected surface pixel format is X8R8G8B8");
816 case D3DFMT_A8R8G8B8
:
817 msg_Dbg( p_vout
, "selected surface pixel format is A8R8G8B8");
820 msg_Dbg( p_vout
, "selected surface pixel format is R8G8B8");
823 msg_Dbg( p_vout
, "selected surface pixel format is R5G6B5");
825 case D3DFMT_X1R5G5B5
:
826 msg_Dbg( p_vout
, "selected surface pixel format is X1R5G5B5");
829 msg_Dbg( p_vout
, "selected surface pixel format is 0x%0X", format
);
834 else if( D3DERR_NOTAVAILABLE
!= hr
)
836 msg_Err( p_vout
, "Could not query adapter supported formats. (hr=0x%lX)", hr
);
840 return D3DFMT_UNKNOWN
;
843 static D3DFORMAT
Direct3DVoutFindFormat(vout_thread_t
*p_vout
, int i_chroma
, D3DFORMAT target
)
845 //if( p_vout->p_sys->b_hw_yuv && ! _got_vista_or_above )
846 if( p_vout
->p_sys
->b_hw_yuv
)
848 /* it sounds like vista does not support YUV surfaces at all */
853 static const D3DFORMAT formats
[] =
854 { D3DFMT_UYVY
, D3DFMT_YUY2
, D3DFMT_X8R8G8B8
, D3DFMT_A8R8G8B8
, D3DFMT_R5G6B5
, D3DFMT_X1R5G5B5
};
855 return Direct3DVoutSelectFormat(p_vout
, target
, formats
, sizeof(formats
)/sizeof(D3DFORMAT
));
861 /* typically 3D textures don't support planar format
862 ** fallback to packed version and use CPU for the conversion
864 static const D3DFORMAT formats
[] =
865 { D3DFMT_YUY2
, D3DFMT_UYVY
, D3DFMT_X8R8G8B8
, D3DFMT_A8R8G8B8
, D3DFMT_R5G6B5
, D3DFMT_X1R5G5B5
};
866 return Direct3DVoutSelectFormat(p_vout
, target
, formats
, sizeof(formats
)/sizeof(D3DFORMAT
));
870 static const D3DFORMAT formats
[] =
871 { D3DFMT_YUY2
, D3DFMT_UYVY
, D3DFMT_X8R8G8B8
, D3DFMT_A8R8G8B8
, D3DFMT_R5G6B5
, D3DFMT_X1R5G5B5
};
872 return Direct3DVoutSelectFormat(p_vout
, target
, formats
, sizeof(formats
)/sizeof(D3DFORMAT
));
879 case VLC_CODEC_RGB15
:
881 static const D3DFORMAT formats
[] =
883 return Direct3DVoutSelectFormat(p_vout
, target
, formats
, sizeof(formats
)/sizeof(D3DFORMAT
));
885 case VLC_CODEC_RGB16
:
887 static const D3DFORMAT formats
[] =
889 return Direct3DVoutSelectFormat(p_vout
, target
, formats
, sizeof(formats
)/sizeof(D3DFORMAT
));
891 case VLC_CODEC_RGB24
:
893 static const D3DFORMAT formats
[] =
894 { D3DFMT_R8G8B8
, D3DFMT_X8R8G8B8
, D3DFMT_A8R8G8B8
};
895 return Direct3DVoutSelectFormat(p_vout
, target
, formats
, sizeof(formats
)/sizeof(D3DFORMAT
));
897 case VLC_CODEC_RGB32
:
899 static const D3DFORMAT formats
[] =
900 { D3DFMT_A8R8G8B8
, D3DFMT_X8R8G8B8
};
901 return Direct3DVoutSelectFormat(p_vout
, target
, formats
, sizeof(formats
)/sizeof(D3DFORMAT
));
905 /* use display default format */
906 LPDIRECT3D9 p_d3dobj
= p_vout
->p_sys
->p_d3dobj
;
907 D3DDISPLAYMODE d3ddm
;
909 HRESULT hr
= IDirect3D9_GetAdapterDisplayMode(p_d3dobj
, D3DADAPTER_DEFAULT
, &d3ddm
);
913 ** some professional cards could use some advanced pixel format as default,
914 ** make sure we stick with chromas that we can handle internally
916 switch( d3ddm
.Format
)
919 case D3DFMT_X8R8G8B8
:
920 case D3DFMT_A8R8G8B8
:
922 case D3DFMT_X1R5G5B5
:
923 msg_Dbg( p_vout
, "defaulting to adapter pixel format");
924 return Direct3DVoutSelectFormat(p_vout
, target
, &d3ddm
.Format
, 1);
927 /* if we fall here, that probably means that we need to render some YUV format */
928 static const D3DFORMAT formats
[] =
929 { D3DFMT_X8R8G8B8
, D3DFMT_A8R8G8B8
, D3DFMT_R5G6B5
, D3DFMT_X1R5G5B5
};
930 msg_Dbg( p_vout
, "defaulting to built-in pixel format");
931 return Direct3DVoutSelectFormat(p_vout
, target
, formats
, sizeof(formats
)/sizeof(D3DFORMAT
));
937 return D3DFMT_UNKNOWN
;
940 static int Direct3DVoutSetOutputFormat(vout_thread_t
*p_vout
, D3DFORMAT format
)
945 p_vout
->output
.i_chroma
= VLC_CODEC_YUYV
;
948 p_vout
->output
.i_chroma
= VLC_CODEC_UYVY
;
951 p_vout
->output
.i_chroma
= VLC_CODEC_RGB24
;
952 p_vout
->output
.i_rmask
= 0xff0000;
953 p_vout
->output
.i_gmask
= 0x00ff00;
954 p_vout
->output
.i_bmask
= 0x0000ff;
956 case D3DFMT_X8R8G8B8
:
957 case D3DFMT_A8R8G8B8
:
958 p_vout
->output
.i_chroma
= VLC_CODEC_RGB32
;
959 p_vout
->output
.i_rmask
= 0x00ff0000;
960 p_vout
->output
.i_gmask
= 0x0000ff00;
961 p_vout
->output
.i_bmask
= 0x000000ff;
964 p_vout
->output
.i_chroma
= VLC_CODEC_RGB16
;
965 p_vout
->output
.i_rmask
= (0x1fL
)<<11;
966 p_vout
->output
.i_gmask
= (0x3fL
)<<5;
967 p_vout
->output
.i_bmask
= (0x1fL
)<<0;
969 case D3DFMT_X1R5G5B5
:
970 p_vout
->output
.i_chroma
= VLC_CODEC_RGB15
;
971 p_vout
->output
.i_rmask
= (0x1fL
)<<10;
972 p_vout
->output
.i_gmask
= (0x1fL
)<<5;
973 p_vout
->output
.i_bmask
= (0x1fL
)<<0;
981 /*****************************************************************************
982 * Direct3DVoutCreatePictures: allocate a vector of identical pictures
983 *****************************************************************************
984 * Each picture has an associated offscreen surface in video memory
985 * depending on hardware capabilities the picture chroma will be as close
986 * as possible to the orginal render chroma to reduce CPU conversion overhead
987 * and delegate this work to video card GPU
988 *****************************************************************************/
989 static int Direct3DVoutCreatePictures( vout_thread_t
*p_vout
, size_t i_num_pics
)
991 LPDIRECT3DDEVICE9 p_d3ddev
= p_vout
->p_sys
->p_d3ddev
;
995 // if vout is already running, use current chroma, otherwise choose from upstream
996 int i_chroma
= p_vout
->output
.i_chroma
? p_vout
->output
.i_chroma
997 : p_vout
->render
.i_chroma
;
999 I_OUTPUTPICTURES
= 0;
1002 ** find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
1003 ** the requested chroma which is usable by the hardware in an offscreen surface, as they
1004 ** typically support more formats than textures
1006 format
= Direct3DVoutFindFormat(p_vout
, i_chroma
, p_vout
->p_sys
->bbFormat
);
1007 if( VLC_SUCCESS
!= Direct3DVoutSetOutputFormat(p_vout
, format
) )
1009 msg_Err(p_vout
, "surface pixel format is not supported.");
1010 return VLC_EGENERIC
;
1013 for( c
=0; c
<i_num_pics
; )
1016 LPDIRECT3DSURFACE9 p_d3dsurf
;
1017 picture_t
*p_pic
= p_vout
->p_picture
+c
;
1019 hr
= IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3ddev
,
1020 p_vout
->render
.i_width
,
1021 p_vout
->render
.i_height
,
1028 msg_Err(p_vout
, "Failed to create picture surface. (hr=0x%lx)", hr
);
1029 Direct3DVoutReleasePictures(p_vout
);
1030 return VLC_EGENERIC
;
1033 /* fill surface with black color */
1034 IDirect3DDevice9_ColorFill(p_d3ddev
, p_d3dsurf
, NULL
, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
1036 /* assign surface to internal structure */
1037 p_pic
->p_sys
= (void *)p_d3dsurf
;
1039 /* Now that we've got our direct-buffer, we can finish filling in the
1040 * picture_t structures */
1041 switch( p_vout
->output
.i_chroma
)
1043 case VLC_CODEC_RGB8
:
1044 p_pic
->p
->i_lines
= p_vout
->output
.i_height
;
1045 p_pic
->p
->i_visible_lines
= p_vout
->output
.i_height
;
1046 p_pic
->p
->i_pixel_pitch
= 1;
1047 p_pic
->p
->i_visible_pitch
= p_vout
->output
.i_width
*
1048 p_pic
->p
->i_pixel_pitch
;
1049 p_pic
->i_planes
= 1;
1051 case VLC_CODEC_RGB15
:
1052 case VLC_CODEC_RGB16
:
1053 p_pic
->p
->i_lines
= p_vout
->output
.i_height
;
1054 p_pic
->p
->i_visible_lines
= p_vout
->output
.i_height
;
1055 p_pic
->p
->i_pixel_pitch
= 2;
1056 p_pic
->p
->i_visible_pitch
= p_vout
->output
.i_width
*
1057 p_pic
->p
->i_pixel_pitch
;
1058 p_pic
->i_planes
= 1;
1060 case VLC_CODEC_RGB24
:
1061 p_pic
->p
->i_lines
= p_vout
->output
.i_height
;
1062 p_pic
->p
->i_visible_lines
= p_vout
->output
.i_height
;
1063 p_pic
->p
->i_pixel_pitch
= 3;
1064 p_pic
->p
->i_visible_pitch
= p_vout
->output
.i_width
*
1065 p_pic
->p
->i_pixel_pitch
;
1066 p_pic
->i_planes
= 1;
1068 case VLC_CODEC_RGB32
:
1069 p_pic
->p
->i_lines
= p_vout
->output
.i_height
;
1070 p_pic
->p
->i_visible_lines
= p_vout
->output
.i_height
;
1071 p_pic
->p
->i_pixel_pitch
= 4;
1072 p_pic
->p
->i_visible_pitch
= p_vout
->output
.i_width
*
1073 p_pic
->p
->i_pixel_pitch
;
1074 p_pic
->i_planes
= 1;
1076 case VLC_CODEC_UYVY
:
1077 case VLC_CODEC_YUYV
:
1078 p_pic
->p
->i_lines
= p_vout
->output
.i_height
;
1079 p_pic
->p
->i_visible_lines
= p_vout
->output
.i_height
;
1080 p_pic
->p
->i_pixel_pitch
= 2;
1081 p_pic
->p
->i_visible_pitch
= p_vout
->output
.i_width
*
1082 p_pic
->p
->i_pixel_pitch
;
1083 p_pic
->i_planes
= 1;
1086 Direct3DVoutReleasePictures(p_vout
);
1087 return VLC_EGENERIC
;
1089 p_pic
->i_status
= DESTROYED_PICTURE
;
1090 p_pic
->i_type
= DIRECT_PICTURE
;
1091 p_pic
->b_slow
= true;
1092 p_pic
->pf_lock
= Direct3DVoutLockSurface
;
1093 p_pic
->pf_unlock
= Direct3DVoutUnlockSurface
;
1094 PP_OUTPUTPICTURE
[c
] = p_pic
;
1096 I_OUTPUTPICTURES
= ++c
;
1099 msg_Dbg( p_vout
, "%u Direct3D pictures created successfully", c
);
1104 /*****************************************************************************
1105 * Direct3DVoutReleasePictures: destroy a picture vector
1106 *****************************************************************************
1107 * release all video resources used for pictures
1108 *****************************************************************************/
1109 static void Direct3DVoutReleasePictures( vout_thread_t
*p_vout
)
1111 size_t i_num_pics
= I_OUTPUTPICTURES
;
1113 for( c
=0; c
<i_num_pics
; ++c
)
1115 picture_t
*p_pic
= p_vout
->p_picture
+c
;
1118 LPDIRECT3DSURFACE9 p_d3dsurf
= (LPDIRECT3DSURFACE9
)p_pic
->p_sys
;
1120 p_pic
->p_sys
= NULL
;
1124 IDirect3DSurface9_Release(p_d3dsurf
);
1128 msg_Dbg( p_vout
, "%u Direct3D pictures released.", c
);
1130 I_OUTPUTPICTURES
= 0;
1133 /*****************************************************************************
1134 * Direct3DVoutLockSurface: Lock surface and get picture data pointer
1135 *****************************************************************************
1136 * This function locks a surface and get the surface descriptor which amongst
1137 * other things has the pointer to the picture data.
1138 *****************************************************************************/
1139 static int Direct3DVoutLockSurface( vout_thread_t
*p_vout
, picture_t
*p_pic
)
1142 D3DLOCKED_RECT d3drect
;
1143 LPDIRECT3DSURFACE9 p_d3dsurf
= (LPDIRECT3DSURFACE9
)p_pic
->p_sys
;
1145 if( NULL
== p_d3dsurf
)
1146 return VLC_EGENERIC
;
1148 /* Lock the surface to get a valid pointer to the picture buffer */
1149 hr
= IDirect3DSurface9_LockRect(p_d3dsurf
, &d3drect
, NULL
, 0);
1152 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1153 return VLC_EGENERIC
;
1156 /* fill in buffer info in first plane */
1157 p_pic
->p
->p_pixels
= d3drect
.pBits
;
1158 p_pic
->p
->i_pitch
= d3drect
.Pitch
;
1163 /*****************************************************************************
1164 * Direct3DVoutUnlockSurface: Unlock a surface locked by Direct3DLockSurface().
1165 *****************************************************************************/
1166 static int Direct3DVoutUnlockSurface( vout_thread_t
*p_vout
, picture_t
*p_pic
)
1169 LPDIRECT3DSURFACE9 p_d3dsurf
= (LPDIRECT3DSURFACE9
)p_pic
->p_sys
;
1171 if( NULL
== p_d3dsurf
)
1172 return VLC_EGENERIC
;
1174 /* Unlock the Surface */
1175 hr
= IDirect3DSurface9_UnlockRect(p_d3dsurf
);
1178 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1179 return VLC_EGENERIC
;
1184 /*****************************************************************************
1185 * Direct3DVoutCreateScene: allocate and initialize a 3D scene
1186 *****************************************************************************
1187 * for advanced blending/filtering a texture needs be used in a 3D scene.
1188 *****************************************************************************/
1190 static int Direct3DVoutCreateScene( vout_thread_t
*p_vout
)
1192 LPDIRECT3DDEVICE9 p_d3ddev
= p_vout
->p_sys
->p_d3ddev
;
1193 LPDIRECT3DTEXTURE9 p_d3dtex
;
1194 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc
;
1199 ** Create a texture for use when rendering a scene
1200 ** for performance reason, texture format is identical to backbuffer
1201 ** which would usually be a RGB format
1203 hr
= IDirect3DDevice9_CreateTexture(p_d3ddev
,
1204 p_vout
->render
.i_width
,
1205 p_vout
->render
.i_height
,
1207 D3DUSAGE_RENDERTARGET
,
1208 p_vout
->p_sys
->bbFormat
,
1214 msg_Err(p_vout
, "Failed to create texture. (hr=0x%lx)", hr
);
1215 return VLC_EGENERIC
;
1219 ** Create a vertex buffer for use when rendering scene
1221 hr
= IDirect3DDevice9_CreateVertexBuffer(p_d3ddev
,
1222 sizeof(CUSTOMVERTEX
)*4,
1223 D3DUSAGE_DYNAMIC
|D3DUSAGE_WRITEONLY
,
1224 D3DFVF_CUSTOMVERTEX
,
1230 msg_Err(p_vout
, "Failed to create vertex buffer. (hr=0x%lx)", hr
);
1231 IDirect3DTexture9_Release(p_d3dtex
);
1232 return VLC_EGENERIC
;
1235 p_vout
->p_sys
->p_d3dtex
= p_d3dtex
;
1236 p_vout
->p_sys
->p_d3dvtc
= p_d3dvtc
;
1238 // Texture coordinates outside the range [0.0, 1.0] are set
1239 // to the texture color at 0.0 or 1.0, respectively.
1240 IDirect3DDevice9_SetSamplerState(p_d3ddev
, 0, D3DSAMP_ADDRESSU
, D3DTADDRESS_CLAMP
);
1241 IDirect3DDevice9_SetSamplerState(p_d3ddev
, 0, D3DSAMP_ADDRESSV
, D3DTADDRESS_CLAMP
);
1243 // Set linear filtering quality
1244 IDirect3DDevice9_SetSamplerState(p_d3ddev
, 0, D3DSAMP_MINFILTER
, D3DTEXF_LINEAR
);
1245 IDirect3DDevice9_SetSamplerState(p_d3ddev
, 0, D3DSAMP_MAGFILTER
, D3DTEXF_LINEAR
);
1247 // set maximum ambient light
1248 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_AMBIENT
, D3DCOLOR_XRGB(255,255,255));
1251 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_CULLMODE
, D3DCULL_NONE
);
1253 // Turn off the zbuffer
1254 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_ZENABLE
, D3DZB_FALSE
);
1257 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_LIGHTING
, FALSE
);
1260 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_DITHERENABLE
, TRUE
);
1263 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_STENCILENABLE
, FALSE
);
1266 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_ALPHABLENDENABLE
, TRUE
);
1267 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_SRCBLEND
,D3DBLEND_SRCALPHA
);
1268 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_DESTBLEND
,D3DBLEND_INVSRCALPHA
);
1269 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_ALPHATESTENABLE
,TRUE
);
1270 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_ALPHAREF
, 0x10);
1271 IDirect3DDevice9_SetRenderState(p_d3ddev
, D3DRS_ALPHAFUNC
,D3DCMP_GREATER
);
1273 // Set texture states
1274 IDirect3DDevice9_SetTextureStageState(p_d3ddev
, 0, D3DTSS_COLOROP
,D3DTOP_MODULATE
);
1275 IDirect3DDevice9_SetTextureStageState(p_d3ddev
, 0, D3DTSS_COLORARG1
,D3DTA_TEXTURE
);
1276 IDirect3DDevice9_SetTextureStageState(p_d3ddev
, 0, D3DTSS_COLORARG2
,D3DTA_DIFFUSE
);
1278 // turn off alpha operation
1279 IDirect3DDevice9_SetTextureStageState(p_d3ddev
, 0, D3DTSS_ALPHAOP
, D3DTOP_DISABLE
);
1281 msg_Dbg( p_vout
, "Direct3D scene created successfully");
1286 /*****************************************************************************
1287 * Direct3DVoutReleaseScene
1288 *****************************************************************************/
1289 static void Direct3DVoutReleaseScene( vout_thread_t
*p_vout
)
1291 LPDIRECT3DTEXTURE9 p_d3dtex
= p_vout
->p_sys
->p_d3dtex
;
1292 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc
= p_vout
->p_sys
->p_d3dvtc
;
1296 IDirect3DVertexBuffer9_Release(p_d3dvtc
);
1297 p_vout
->p_sys
->p_d3dvtc
= NULL
;
1302 IDirect3DTexture9_Release(p_d3dtex
);
1303 p_vout
->p_sys
->p_d3dtex
= NULL
;
1305 msg_Dbg( p_vout
, "Direct3D scene released successfully");
1308 /*****************************************************************************
1309 * Render: copy picture surface into a texture and render into a scene
1310 *****************************************************************************
1311 * This function is intented for higher end 3D cards, with pixel shader support
1312 * and at least 64 MB of video RAM.
1313 *****************************************************************************/
1314 static void Direct3DVoutRenderScene( vout_thread_t
*p_vout
, picture_t
*p_pic
)
1316 LPDIRECT3DDEVICE9 p_d3ddev
= p_vout
->p_sys
->p_d3ddev
;
1317 LPDIRECT3DTEXTURE9 p_d3dtex
;
1318 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc
;
1319 LPDIRECT3DSURFACE9 p_d3dsrc
, p_d3ddest
;
1320 CUSTOMVERTEX
*p_vertices
;
1322 float f_width
, f_height
;
1324 if( p_vout
->p_sys
->i_changes
& SWITCHING_MODE_FLAG
)
1327 // check if device is still available
1328 hr
= IDirect3DDevice9_TestCooperativeLevel(p_d3ddev
);
1331 if( (D3DERR_DEVICENOTRESET
!= hr
)
1332 || (VLC_SUCCESS
!= Direct3DVoutResetDevice(p_vout
)) )
1334 // device is not usable at present (lost device, out of video mem ?)
1338 p_d3dtex
= p_vout
->p_sys
->p_d3dtex
;
1339 p_d3dvtc
= p_vout
->p_sys
->p_d3dvtc
;
1341 /* Clear the backbuffer and the zbuffer */
1342 hr
= IDirect3DDevice9_Clear( p_d3ddev
, 0, NULL
, D3DCLEAR_TARGET
,
1343 D3DCOLOR_XRGB(0, 0, 0), 1.0f
, 0 );
1346 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1350 /* retrieve picture surface */
1351 p_d3dsrc
= (LPDIRECT3DSURFACE9
)p_pic
->p_sys
;
1352 if( NULL
== p_d3dsrc
)
1354 msg_Dbg( p_vout
, "no surface to render ?");
1358 /* retrieve texture top-level surface */
1359 hr
= IDirect3DTexture9_GetSurfaceLevel(p_d3dtex
, 0, &p_d3ddest
);
1362 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1366 /* Copy picture surface into texture surface, color space conversion happens here */
1367 hr
= IDirect3DDevice9_StretchRect(p_d3ddev
, p_d3dsrc
, NULL
, p_d3ddest
, NULL
, D3DTEXF_NONE
);
1368 IDirect3DSurface9_Release(p_d3ddest
);
1371 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1375 /* Update the vertex buffer */
1376 hr
= IDirect3DVertexBuffer9_Lock(p_d3dvtc
, 0, 0, (VOID
**)(&p_vertices
), D3DLOCK_DISCARD
);
1379 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1383 /* Setup vertices */
1384 f_width
= (float)(p_vout
->output
.i_width
);
1385 f_height
= (float)(p_vout
->output
.i_height
);
1387 /* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */
1388 /* http://www.sjbrown.co.uk/2003/05/01/fix-directx-rasterisation/ */
1389 p_vertices
[0].x
= -0.5f
; // left
1390 p_vertices
[0].y
= -0.5f
; // top
1391 p_vertices
[0].z
= 0.0f
;
1392 p_vertices
[0].diffuse
= D3DCOLOR_ARGB(255, 255, 255, 255);
1393 p_vertices
[0].rhw
= 1.0f
;
1394 p_vertices
[0].tu
= 0.0f
;
1395 p_vertices
[0].tv
= 0.0f
;
1397 p_vertices
[1].x
= f_width
- 0.5f
; // right
1398 p_vertices
[1].y
= -0.5f
; // top
1399 p_vertices
[1].z
= 0.0f
;
1400 p_vertices
[1].diffuse
= D3DCOLOR_ARGB(255, 255, 255, 255);
1401 p_vertices
[1].rhw
= 1.0f
;
1402 p_vertices
[1].tu
= 1.0f
;
1403 p_vertices
[1].tv
= 0.0f
;
1405 p_vertices
[2].x
= f_width
- 0.5f
; // right
1406 p_vertices
[2].y
= f_height
- 0.5f
; // bottom
1407 p_vertices
[2].z
= 0.0f
;
1408 p_vertices
[2].diffuse
= D3DCOLOR_ARGB(255, 255, 255, 255);
1409 p_vertices
[2].rhw
= 1.0f
;
1410 p_vertices
[2].tu
= 1.0f
;
1411 p_vertices
[2].tv
= 1.0f
;
1413 p_vertices
[3].x
= -0.5f
; // left
1414 p_vertices
[3].y
= f_height
- 0.5f
; // bottom
1415 p_vertices
[3].z
= 0.0f
;
1416 p_vertices
[3].diffuse
= D3DCOLOR_ARGB(255, 255, 255, 255);
1417 p_vertices
[3].rhw
= 1.0f
;
1418 p_vertices
[3].tu
= 0.0f
;
1419 p_vertices
[3].tv
= 1.0f
;
1421 hr
= IDirect3DVertexBuffer9_Unlock(p_d3dvtc
);
1424 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1429 hr
= IDirect3DDevice9_BeginScene(p_d3ddev
);
1432 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1436 // Setup our texture. Using textures introduces the texture stage states,
1437 // which govern how textures get blended together (in the case of multiple
1438 // textures) and lighting information. In this case, we are modulating
1439 // (blending) our texture with the diffuse color of the vertices.
1440 hr
= IDirect3DDevice9_SetTexture(p_d3ddev
, 0, (LPDIRECT3DBASETEXTURE9
)p_d3dtex
);
1443 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1444 IDirect3DDevice9_EndScene(p_d3ddev
);
1448 // Render the vertex buffer contents
1449 hr
= IDirect3DDevice9_SetStreamSource(p_d3ddev
, 0, p_d3dvtc
, 0, sizeof(CUSTOMVERTEX
));
1452 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1453 IDirect3DDevice9_EndScene(p_d3ddev
);
1457 // we use FVF instead of vertex shader
1458 hr
= IDirect3DDevice9_SetFVF(p_d3ddev
, D3DFVF_CUSTOMVERTEX
);
1461 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1462 IDirect3DDevice9_EndScene(p_d3ddev
);
1467 hr
= IDirect3DDevice9_DrawPrimitive(p_d3ddev
, D3DPT_TRIANGLEFAN
, 0, 2);
1470 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1471 IDirect3DDevice9_EndScene(p_d3ddev
);
1476 hr
= IDirect3DDevice9_EndScene(p_d3ddev
);
1479 msg_Dbg( p_vout
, "%s:%d (hr=0x%0lX)", __FUNCTION__
, __LINE__
, hr
);
1485 /*****************************************************************************
1486 * DesktopCallback: desktop mode variable callback
1487 *****************************************************************************/
1488 static int DesktopCallback( vlc_object_t
*p_this
, char const *psz_cmd
,
1489 vlc_value_t oldval
, vlc_value_t newval
,
1492 VLC_UNUSED( psz_cmd
);
1493 VLC_UNUSED( oldval
);
1494 VLC_UNUSED( p_data
);
1496 vout_thread_t
*p_vout
= (vout_thread_t
*)p_this
;
1498 if( (newval
.b_bool
&& !p_vout
->p_sys
->b_desktop
) ||
1499 (!newval
.b_bool
&& p_vout
->p_sys
->b_desktop
) )
1501 playlist_t
*p_playlist
= pl_Hold( p_vout
);
1505 /* Modify playlist as well because the vout might have to be
1507 var_Create( p_playlist
, "direct3d-desktop", VLC_VAR_BOOL
);
1508 var_Set( p_playlist
, "direct3d-desktop", newval
);
1509 pl_Release( p_vout
);
1512 p_vout
->p_sys
->i_changes
|= DX_DESKTOP_CHANGE
;