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 /*****************************************************************************
85 *****************************************************************************/
87 static bool IsVistaOrAbove(void)
90 winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
92 if( GetVersionEx(&winVer) )
94 if( winVer.dwMajorVersion > 5 )
96 /* Windows Vista or above, make this module the default */
100 /* Windows XP or lower, make sure this module isn't the default */
104 static int OpenVideoXP( vlc_object_t *obj )
106 return IsVistaOrAbove() ? VLC_EGENERIC : OpenVideo( obj );
109 static int OpenVideoVista( vlc_object_t *obj )
111 return IsVistaOrAbove() ? OpenVideo( obj ) : VLC_EGENERIC;
115 set_shortname( "Direct3D" )
116 set_category( CAT_VIDEO )
117 set_subcategory( SUBCAT_VIDEO_VOUT )
118 set_description( N_("DirectX 3D video output") )
119 set_capability( "video output", 50 )
120 add_shortcut( "direct3d" )
121 set_callbacks( OpenVideoXP, CloseVideo )
123 /* FIXME: Hack to avoid unregistering our window class */
124 linked_with_a_crap_library_which_uses_atexit ()
127 set_capability( "video output", 150 )
128 add_shortcut( "direct3d" )
129 set_callbacks( OpenVideoVista, CloseVideo )
133 /* check if we registered a window class because we need to
136 if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
137 UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
140 /*****************************************************************************
142 *****************************************************************************
143 *****************************************************************************/
146 FLOAT x,y,z; // vertex untransformed position
147 FLOAT rhw; // eye distance
148 D3DCOLOR diffuse; // diffuse color
149 FLOAT tu, tv; // texture relative coordinates
152 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
154 /*****************************************************************************
155 * OpenVideo: allocate Vout video thread output method
156 *****************************************************************************
157 * This function allocates and initialize the Direct3D vout method.
158 *****************************************************************************/
159 static int OpenVideo( vlc_object_t *p_this )
161 vout_thread_t * p_vout = (vout_thread_t *)p_this;
163 /* Allocate structure */
164 p_vout->p_sys = calloc( 1, sizeof( vout_sys_t ) );
165 if( p_vout->p_sys == NULL )
168 if( VLC_SUCCESS != Direct3DVoutCreate( p_vout ) )
170 msg_Err( p_vout, "Direct3D could not be initialized !");
171 Direct3DVoutRelease( p_vout );
172 free( p_vout->p_sys );
176 /* Initialisations */
177 p_vout->pf_init = Init;
178 p_vout->pf_end = End;
179 p_vout->pf_manage = Manage;
180 p_vout->pf_render = Direct3DVoutRenderScene;
181 p_vout->pf_display = FirstDisplay;
183 p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
184 p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
185 p_vout->p_sys->i_changes = 0;
186 vlc_mutex_init( &p_vout->p_sys->lock );
187 SetRectEmpty( &p_vout->p_sys->rect_display );
188 SetRectEmpty( &p_vout->p_sys->rect_parent );
190 var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
191 var_Create( p_vout, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
193 p_vout->p_sys->b_cursor_hidden = 0;
194 p_vout->p_sys->i_lastmoved = mdate();
195 p_vout->p_sys->i_mouse_hide_timeout =
196 var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
198 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
199 var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
201 /* Set main window's size */
202 p_vout->p_sys->i_window_width = p_vout->i_window_width;
203 p_vout->p_sys->i_window_height = p_vout->i_window_height;
205 if ( CreateEventThread( p_vout ) )
207 /* Variable to indicate if the window should be on top of others */
208 /* Trigger a callback right now */
209 var_TriggerCallback( p_vout, "video-on-top" );
211 DisableScreensaver ( p_vout );
217 CloseVideo( VLC_OBJECT(p_vout) );
222 /*****************************************************************************
223 * CloseVideo: destroy Sys video thread output method
224 *****************************************************************************
225 * Terminate an output method created by Create
226 *****************************************************************************/
227 static void CloseVideo( vlc_object_t *p_this )
229 vout_thread_t * p_vout = (vout_thread_t *)p_this;
231 Direct3DVoutRelease( p_vout );
233 StopEventThread( p_vout );
235 RestoreScreensaver( p_vout );
237 free( p_vout->p_sys );
238 p_vout->p_sys = NULL;
241 /*****************************************************************************
242 * Init: initialize Direct3D video thread output method
243 *****************************************************************************/
244 static int Init( vout_thread_t *p_vout )
248 p_vout->p_sys->b_hw_yuv = var_GetBool( p_vout, "directx-hw-yuv" );
250 /* Initialise Direct3D */
251 if( VLC_SUCCESS != Direct3DVoutOpen( p_vout ) )
253 msg_Err( p_vout, "cannot initialize Direct3D" );
257 /* Initialize the output structure.
258 * Since Direct3D can do rescaling for us, stick to the default
259 * coordinates and aspect. */
260 p_vout->output.i_width = p_vout->render.i_width;
261 p_vout->output.i_height = p_vout->render.i_height;
262 p_vout->output.i_aspect = p_vout->render.i_aspect;
263 p_vout->fmt_out = p_vout->fmt_in;
264 UpdateRects( p_vout, true );
266 /* create picture pool */
267 p_vout->output.i_chroma = 0;
268 i_ret = Direct3DVoutCreatePictures(p_vout, 1);
269 if( VLC_SUCCESS != i_ret )
271 msg_Err(p_vout, "Direct3D picture pool initialization failed !");
276 i_ret = Direct3DVoutCreateScene(p_vout);
277 if( VLC_SUCCESS != i_ret )
279 msg_Err(p_vout, "Direct3D scene initialization failed !");
280 Direct3DVoutReleasePictures(p_vout);
284 /* Change the window title bar text */
285 PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
287 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
291 /*****************************************************************************
292 * End: terminate Sys video thread output method
293 *****************************************************************************
294 * Terminate an output method created by Create.
295 * It is called at the end of the thread.
296 *****************************************************************************/
297 static void End( vout_thread_t *p_vout )
299 Direct3DVoutReleaseScene(p_vout);
300 Direct3DVoutReleasePictures(p_vout);
301 Direct3DVoutClose( p_vout );
304 /*****************************************************************************
305 * Manage: handle Sys events
306 *****************************************************************************
307 * This function should be called regularly by the video output thread.
308 * It returns a non null value if an error occurred.
309 *****************************************************************************/
310 static int Manage( vout_thread_t *p_vout )
312 /* If we do not control our window, we check for geometry changes
313 * ourselves because the parent might not send us its events. */
314 vlc_mutex_lock( &p_vout->p_sys->lock );
315 if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
320 vlc_mutex_unlock( &p_vout->p_sys->lock );
322 GetClientRect( p_vout->p_sys->hparent, &rect_parent );
323 point.x = point.y = 0;
324 ClientToScreen( p_vout->p_sys->hparent, &point );
325 OffsetRect( &rect_parent, point.x, point.y );
327 if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
329 p_vout->p_sys->rect_parent = rect_parent;
331 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
332 rect_parent.right - rect_parent.left,
333 rect_parent.bottom - rect_parent.top,
339 vlc_mutex_unlock( &p_vout->p_sys->lock );
345 if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
347 #if 0 /* need that when bicubic filter is available */
351 GetClientRect(p_vout->p_sys->hvideownd, &rect);
352 width = rect.right-rect.left;
353 height = rect.bottom-rect.top;
355 if( (width != p_vout->p_sys->d3dpp.BackBufferWidth)
356 || (height != p_vout->p_sys->d3dpp.BackBufferHeight) )
358 msg_Dbg(p_vout, "resizing device back buffers to (%lux%lu)", width, height);
359 // need to reset D3D device to resize back buffer
360 if( VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, width, height) )
364 p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
367 /* autoscale toggle */
368 if( p_vout->i_changes & VOUT_SCALE_CHANGE )
370 p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
372 p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
373 p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
375 UpdateRects( p_vout, true );
379 if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
381 p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
383 p_vout->b_autoscale = false;
385 (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
386 UpdateRects( p_vout, true );
389 /* Check for cropping / aspect changes */
390 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
391 p_vout->i_changes & VOUT_ASPECT_CHANGE )
393 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
394 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
396 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
397 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
398 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
399 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
400 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
401 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
402 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
403 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
404 UpdateRects( p_vout, true );
407 /* We used to call the Win32 PeekMessage function here to read the window
408 * messages. But since window can stay blocked into this function for a
409 * long time (for example when you move your window on the screen), I
410 * decided to isolate PeekMessage in another thread. */
415 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
416 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
418 Win32ToggleFullscreen( p_vout );
420 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
421 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
427 if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
428 (mdate() - p_vout->p_sys->i_lastmoved) >
429 p_vout->p_sys->i_mouse_hide_timeout )
434 /* Hide the cursor only if it is inside our window */
435 GetCursorPos( &point );
436 hwnd = WindowFromPoint(point);
437 if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
439 PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
443 p_vout->p_sys->i_lastmoved = mdate();
448 * "Always on top" status change
450 if( p_vout->p_sys->b_on_top_change )
453 HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
455 var_Get( p_vout, "video-on-top", &val );
457 /* Set the window on top if necessary */
458 if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
461 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
462 MF_BYCOMMAND | MFS_CHECKED );
463 SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
464 SWP_NOSIZE | SWP_NOMOVE );
467 /* The window shouldn't be on top */
468 if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
471 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
472 MF_BYCOMMAND | MFS_UNCHECKED );
473 SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
474 SWP_NOSIZE | SWP_NOMOVE );
477 p_vout->p_sys->b_on_top_change = false;
480 /* Check if the event thread is still running */
481 if( !vlc_object_alive (p_vout->p_sys->p_event) )
483 return VLC_EGENERIC; /* exit */
489 /*****************************************************************************
490 * Display: displays previously rendered output
491 *****************************************************************************
492 * This function sends the currently rendered image to the display, wait until
493 * it is displayed and switch the two rendering buffers, preparing next frame.
494 *****************************************************************************/
495 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
497 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
498 // Present the back buffer contents to the display
499 // stretching and filtering happens here
500 HRESULT hr = IDirect3DDevice9_Present(p_d3ddev,
501 &(p_vout->p_sys->rect_src_clipped),
504 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
508 ** this function is only used once when the first picture is received
509 ** this function will show the video window once a picture is ready
512 static void FirstDisplay( vout_thread_t *p_vout, picture_t *p_pic )
514 /* get initial picture presented through D3D */
515 Display(p_vout, p_pic);
518 ** Video window is initially hidden, show it now since we got a
521 SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
529 /* use and restores proper display function for further pictures */
530 p_vout->pf_display = Display;
533 /*****************************************************************************
534 * DirectD3DVoutCreate: Initialize and instance of Direct3D9
535 *****************************************************************************
536 * This function initialize Direct3D and analyze available resources from
538 *****************************************************************************/
539 static int Direct3DVoutCreate( vout_thread_t *p_vout )
542 LPDIRECT3D9 p_d3dobj;
545 LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
547 p_vout->p_sys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
548 if( NULL == p_vout->p_sys->hd3d9_dll )
550 msg_Warn( p_vout, "cannot load d3d9.dll, aborting" );
555 (void *)GetProcAddress( p_vout->p_sys->hd3d9_dll,
556 TEXT("Direct3DCreate9") );
557 if( OurDirect3DCreate9 == NULL )
559 msg_Err( p_vout, "Cannot locate reference to Direct3DCreate9 ABI in DLL" );
563 /* Create the D3D object. */
564 p_d3dobj = OurDirect3DCreate9( D3D_SDK_VERSION );
565 if( NULL == p_d3dobj )
567 msg_Err( p_vout, "Could not create Direct3D9 instance.");
570 p_vout->p_sys->p_d3dobj = p_d3dobj;
573 ** Get device capabilities
575 ZeroMemory(&d3dCaps, sizeof(d3dCaps));
576 hr = IDirect3D9_GetDeviceCaps(p_d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps);
579 msg_Err( p_vout, "Could not read adapter capabilities. (hr=0x%lX)", hr);
582 /* TODO: need to test device capabilities and select the right render function */
587 /*****************************************************************************
588 * DirectD3DVoutRelease: release an instance of Direct3D9
589 *****************************************************************************/
591 static void Direct3DVoutRelease( vout_thread_t *p_vout )
593 if( p_vout->p_sys->p_d3dobj )
595 IDirect3D9_Release(p_vout->p_sys->p_d3dobj);
596 p_vout->p_sys->p_d3dobj = NULL;
598 if( NULL != p_vout->p_sys->hd3d9_dll )
600 FreeLibrary(p_vout->p_sys->hd3d9_dll);
601 p_vout->p_sys->hd3d9_dll = NULL;
605 static int Direct3DFillPresentationParameters(vout_thread_t *p_vout, D3DPRESENT_PARAMETERS *d3dpp)
607 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
608 D3DDISPLAYMODE d3ddm;
612 ** Get the current desktop display mode, so we can set up a back
613 ** buffer of the same format
615 hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
618 msg_Err( p_vout, "Could not read adapter display mode. (hr=0x%lX)", hr);
622 /* keep a copy of current desktop format */
623 p_vout->p_sys->bbFormat = d3ddm.Format;
625 /* Set up the structure used to create the D3DDevice. */
626 ZeroMemory( d3dpp, sizeof(D3DPRESENT_PARAMETERS) );
627 d3dpp->Flags = D3DPRESENTFLAG_VIDEO;
628 d3dpp->Windowed = TRUE;
629 d3dpp->hDeviceWindow = p_vout->p_sys->hvideownd;
630 d3dpp->BackBufferWidth = p_vout->output.i_width;
631 d3dpp->BackBufferHeight = p_vout->output.i_height;
632 d3dpp->SwapEffect = D3DSWAPEFFECT_COPY;
633 d3dpp->MultiSampleType = D3DMULTISAMPLE_NONE;
634 d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
635 d3dpp->BackBufferFormat = d3ddm.Format;
636 d3dpp->BackBufferCount = 1;
637 d3dpp->EnableAutoDepthStencil = FALSE;
642 /*****************************************************************************
643 * DirectD3DVoutOpen: Takes care of all the Direct3D9 initialisations
644 *****************************************************************************
645 * This function creates Direct3D device
646 * this must be called from the vout thread for performance reason, as
647 * all Direct3D Device APIs are used in a non multithread safe environment
648 *****************************************************************************/
649 static int Direct3DVoutOpen( vout_thread_t *p_vout )
651 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
652 LPDIRECT3DDEVICE9 p_d3ddev;
653 D3DPRESENT_PARAMETERS d3dpp;
656 if( VLC_SUCCESS != Direct3DFillPresentationParameters(p_vout, &d3dpp) )
659 // Create the D3DDevice
660 hr = IDirect3D9_CreateDevice(p_d3dobj, D3DADAPTER_DEFAULT,
661 D3DDEVTYPE_HAL, p_vout->p_sys->hvideownd,
662 D3DCREATE_SOFTWARE_VERTEXPROCESSING|
663 D3DCREATE_MULTITHREADED,
667 msg_Err(p_vout, "Could not create the D3D device! (hr=0x%lX)", hr);
670 p_vout->p_sys->p_d3ddev = p_d3ddev;
672 msg_Dbg( p_vout, "Direct3D device adapter successfully initialized" );
676 /*****************************************************************************
677 * DirectD3DClose: release the Direct3D9 device
678 *****************************************************************************/
679 static void Direct3DVoutClose( vout_thread_t *p_vout )
681 if( p_vout->p_sys->p_d3ddev )
683 IDirect3DDevice9_Release(p_vout->p_sys->p_d3ddev);
684 p_vout->p_sys->p_d3ddev = NULL;
687 p_vout->p_sys->hmonitor = NULL;
690 /*****************************************************************************
691 * DirectD3DClose: reset the Direct3D9 device
692 *****************************************************************************
693 * All resources must be deallocated before the reset occur, they will be
694 * realllocated once the reset has been performed successfully
695 *****************************************************************************/
696 static int Direct3DVoutResetDevice( vout_thread_t *p_vout )
698 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
699 D3DPRESENT_PARAMETERS d3dpp;
702 if( VLC_SUCCESS != Direct3DFillPresentationParameters(p_vout, &d3dpp) )
705 // release all D3D objects
706 Direct3DVoutReleaseScene( p_vout );
707 Direct3DVoutReleasePictures( p_vout );
709 hr = IDirect3DDevice9_Reset(p_d3ddev, &d3dpp);
713 if( (VLC_SUCCESS != Direct3DVoutCreatePictures(p_vout, 1))
714 || (VLC_SUCCESS != Direct3DVoutCreateScene(p_vout)) )
716 msg_Dbg(p_vout, "%s failed !", __FUNCTION__);
721 msg_Err(p_vout, "%s failed ! (hr=%08lX)", __FUNCTION__, hr);
727 static D3DFORMAT Direct3DVoutSelectFormat( vout_thread_t *p_vout, D3DFORMAT target,
728 const D3DFORMAT *formats, size_t count)
730 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
733 for( c=0; c<count; ++c )
736 D3DFORMAT format = formats[c];
737 /* test whether device can create a surface of that format */
738 hr = IDirect3D9_CheckDeviceFormat(p_d3dobj, D3DADAPTER_DEFAULT,
739 D3DDEVTYPE_HAL, target, 0, D3DRTYPE_SURFACE, format);
742 /* test whether device can perform color-conversion
743 ** from that format to target format
745 hr = IDirect3D9_CheckDeviceFormatConversion(p_d3dobj,
746 D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
751 // found a compatible format
755 msg_Dbg( p_vout, "selected surface pixel format is UYVY");
758 msg_Dbg( p_vout, "selected surface pixel format is YUY2");
760 case D3DFMT_X8R8G8B8:
761 msg_Dbg( p_vout, "selected surface pixel format is X8R8G8B8");
763 case D3DFMT_A8R8G8B8:
764 msg_Dbg( p_vout, "selected surface pixel format is A8R8G8B8");
767 msg_Dbg( p_vout, "selected surface pixel format is R8G8B8");
770 msg_Dbg( p_vout, "selected surface pixel format is R5G6B5");
772 case D3DFMT_X1R5G5B5:
773 msg_Dbg( p_vout, "selected surface pixel format is X1R5G5B5");
776 msg_Dbg( p_vout, "selected surface pixel format is 0x%0X", format);
781 else if( D3DERR_NOTAVAILABLE != hr )
783 msg_Err( p_vout, "Could not query adapter supported formats. (hr=0x%lX)", hr);
787 return D3DFMT_UNKNOWN;
790 static D3DFORMAT Direct3DVoutFindFormat(vout_thread_t *p_vout, int i_chroma, D3DFORMAT target)
792 //if( p_vout->p_sys->b_hw_yuv && ! _got_vista_or_above )
793 if( p_vout->p_sys->b_hw_yuv )
795 /* it sounds like vista does not support YUV surfaces at all */
800 static const D3DFORMAT formats[] =
801 { D3DFMT_UYVY, D3DFMT_YUY2, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
802 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
808 /* typically 3D textures don't support planar format
809 ** fallback to packed version and use CPU for the conversion
811 static const D3DFORMAT formats[] =
812 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
813 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
817 static const D3DFORMAT formats[] =
818 { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
819 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
826 case VLC_CODEC_RGB15:
828 static const D3DFORMAT formats[] =
830 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
832 case VLC_CODEC_RGB16:
834 static const D3DFORMAT formats[] =
836 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
838 case VLC_CODEC_RGB24:
840 static const D3DFORMAT formats[] =
841 { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
842 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
844 case VLC_CODEC_RGB32:
846 static const D3DFORMAT formats[] =
847 { D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8 };
848 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
852 /* use display default format */
853 LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj;
854 D3DDISPLAYMODE d3ddm;
856 HRESULT hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm );
860 ** some professional cards could use some advanced pixel format as default,
861 ** make sure we stick with chromas that we can handle internally
863 switch( d3ddm.Format )
866 case D3DFMT_X8R8G8B8:
867 case D3DFMT_A8R8G8B8:
869 case D3DFMT_X1R5G5B5:
870 msg_Dbg( p_vout, "defaulting to adapter pixel format");
871 return Direct3DVoutSelectFormat(p_vout, target, &d3ddm.Format, 1);
874 /* if we fall here, that probably means that we need to render some YUV format */
875 static const D3DFORMAT formats[] =
876 { D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
877 msg_Dbg( p_vout, "defaulting to built-in pixel format");
878 return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
884 return D3DFMT_UNKNOWN;
887 static int Direct3DVoutSetOutputFormat(vout_thread_t *p_vout, D3DFORMAT format)
892 p_vout->output.i_chroma = VLC_CODEC_YUYV;
895 p_vout->output.i_chroma = VLC_CODEC_UYVY;
898 p_vout->output.i_chroma = VLC_CODEC_RGB24;
899 p_vout->output.i_rmask = 0xff0000;
900 p_vout->output.i_gmask = 0x00ff00;
901 p_vout->output.i_bmask = 0x0000ff;
903 case D3DFMT_X8R8G8B8:
904 case D3DFMT_A8R8G8B8:
905 p_vout->output.i_chroma = VLC_CODEC_RGB32;
906 p_vout->output.i_rmask = 0x00ff0000;
907 p_vout->output.i_gmask = 0x0000ff00;
908 p_vout->output.i_bmask = 0x000000ff;
911 p_vout->output.i_chroma = VLC_CODEC_RGB16;
912 p_vout->output.i_rmask = (0x1fL)<<11;
913 p_vout->output.i_gmask = (0x3fL)<<5;
914 p_vout->output.i_bmask = (0x1fL)<<0;
916 case D3DFMT_X1R5G5B5:
917 p_vout->output.i_chroma = VLC_CODEC_RGB15;
918 p_vout->output.i_rmask = (0x1fL)<<10;
919 p_vout->output.i_gmask = (0x1fL)<<5;
920 p_vout->output.i_bmask = (0x1fL)<<0;
928 /*****************************************************************************
929 * Direct3DVoutCreatePictures: allocate a vector of identical pictures
930 *****************************************************************************
931 * Each picture has an associated offscreen surface in video memory
932 * depending on hardware capabilities the picture chroma will be as close
933 * as possible to the orginal render chroma to reduce CPU conversion overhead
934 * and delegate this work to video card GPU
935 *****************************************************************************/
936 static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics )
938 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
942 // if vout is already running, use current chroma, otherwise choose from upstream
943 int i_chroma = p_vout->output.i_chroma ? p_vout->output.i_chroma
944 : p_vout->render.i_chroma;
946 I_OUTPUTPICTURES = 0;
949 ** find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
950 ** the requested chroma which is usable by the hardware in an offscreen surface, as they
951 ** typically support more formats than textures
953 format = Direct3DVoutFindFormat(p_vout, i_chroma, p_vout->p_sys->bbFormat);
954 if( VLC_SUCCESS != Direct3DVoutSetOutputFormat(p_vout, format) )
956 msg_Err(p_vout, "surface pixel format is not supported.");
960 for( c=0; c<i_num_pics; )
963 LPDIRECT3DSURFACE9 p_d3dsurf;
964 picture_t *p_pic = p_vout->p_picture+c;
966 hr = IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3ddev,
967 p_vout->render.i_width,
968 p_vout->render.i_height,
975 msg_Err(p_vout, "Failed to create picture surface. (hr=0x%lx)", hr);
976 Direct3DVoutReleasePictures(p_vout);
980 /* fill surface with black color */
981 IDirect3DDevice9_ColorFill(p_d3ddev, p_d3dsurf, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
983 /* assign surface to internal structure */
984 p_pic->p_sys = (void *)p_d3dsurf;
986 /* Now that we've got our direct-buffer, we can finish filling in the
987 * picture_t structures */
988 switch( p_vout->output.i_chroma )
991 p_pic->p->i_lines = p_vout->output.i_height;
992 p_pic->p->i_visible_lines = p_vout->output.i_height;
993 p_pic->p->i_pixel_pitch = 1;
994 p_pic->p->i_visible_pitch = p_vout->output.i_width *
995 p_pic->p->i_pixel_pitch;
998 case VLC_CODEC_RGB15:
999 case VLC_CODEC_RGB16:
1000 p_pic->p->i_lines = p_vout->output.i_height;
1001 p_pic->p->i_visible_lines = p_vout->output.i_height;
1002 p_pic->p->i_pixel_pitch = 2;
1003 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1004 p_pic->p->i_pixel_pitch;
1005 p_pic->i_planes = 1;
1007 case VLC_CODEC_RGB24:
1008 p_pic->p->i_lines = p_vout->output.i_height;
1009 p_pic->p->i_visible_lines = p_vout->output.i_height;
1010 p_pic->p->i_pixel_pitch = 3;
1011 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1012 p_pic->p->i_pixel_pitch;
1013 p_pic->i_planes = 1;
1015 case VLC_CODEC_RGB32:
1016 p_pic->p->i_lines = p_vout->output.i_height;
1017 p_pic->p->i_visible_lines = p_vout->output.i_height;
1018 p_pic->p->i_pixel_pitch = 4;
1019 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1020 p_pic->p->i_pixel_pitch;
1021 p_pic->i_planes = 1;
1023 case VLC_CODEC_UYVY:
1024 case VLC_CODEC_YUYV:
1025 p_pic->p->i_lines = p_vout->output.i_height;
1026 p_pic->p->i_visible_lines = p_vout->output.i_height;
1027 p_pic->p->i_pixel_pitch = 2;
1028 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1029 p_pic->p->i_pixel_pitch;
1030 p_pic->i_planes = 1;
1033 Direct3DVoutReleasePictures(p_vout);
1034 return VLC_EGENERIC;
1036 p_pic->i_status = DESTROYED_PICTURE;
1037 p_pic->i_type = DIRECT_PICTURE;
1038 p_pic->b_slow = true;
1039 p_pic->pf_lock = Direct3DVoutLockSurface;
1040 p_pic->pf_unlock = Direct3DVoutUnlockSurface;
1041 PP_OUTPUTPICTURE[c] = p_pic;
1043 I_OUTPUTPICTURES = ++c;
1046 msg_Dbg( p_vout, "%u Direct3D pictures created successfully", c );
1051 /*****************************************************************************
1052 * Direct3DVoutReleasePictures: destroy a picture vector
1053 *****************************************************************************
1054 * release all video resources used for pictures
1055 *****************************************************************************/
1056 static void Direct3DVoutReleasePictures( vout_thread_t *p_vout)
1058 size_t i_num_pics = I_OUTPUTPICTURES;
1060 for( c=0; c<i_num_pics; ++c )
1062 picture_t *p_pic = p_vout->p_picture+c;
1065 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1067 p_pic->p_sys = NULL;
1071 IDirect3DSurface9_Release(p_d3dsurf);
1075 msg_Dbg( p_vout, "%u Direct3D pictures released.", c);
1077 I_OUTPUTPICTURES = 0;
1080 /*****************************************************************************
1081 * Direct3DVoutLockSurface: Lock surface and get picture data pointer
1082 *****************************************************************************
1083 * This function locks a surface and get the surface descriptor which amongst
1084 * other things has the pointer to the picture data.
1085 *****************************************************************************/
1086 static int Direct3DVoutLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1089 D3DLOCKED_RECT d3drect;
1090 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1092 if( NULL == p_d3dsurf )
1093 return VLC_EGENERIC;
1095 /* Lock the surface to get a valid pointer to the picture buffer */
1096 hr = IDirect3DSurface9_LockRect(p_d3dsurf, &d3drect, NULL, 0);
1099 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1100 return VLC_EGENERIC;
1103 /* fill in buffer info in first plane */
1104 p_pic->p->p_pixels = d3drect.pBits;
1105 p_pic->p->i_pitch = d3drect.Pitch;
1110 /*****************************************************************************
1111 * Direct3DVoutUnlockSurface: Unlock a surface locked by Direct3DLockSurface().
1112 *****************************************************************************/
1113 static int Direct3DVoutUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1116 LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1118 if( NULL == p_d3dsurf )
1119 return VLC_EGENERIC;
1121 /* Unlock the Surface */
1122 hr = IDirect3DSurface9_UnlockRect(p_d3dsurf);
1125 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1126 return VLC_EGENERIC;
1131 /*****************************************************************************
1132 * Direct3DVoutCreateScene: allocate and initialize a 3D scene
1133 *****************************************************************************
1134 * for advanced blending/filtering a texture needs be used in a 3D scene.
1135 *****************************************************************************/
1137 static int Direct3DVoutCreateScene( vout_thread_t *p_vout )
1139 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1140 LPDIRECT3DTEXTURE9 p_d3dtex;
1141 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
1146 ** Create a texture for use when rendering a scene
1147 ** for performance reason, texture format is identical to backbuffer
1148 ** which would usually be a RGB format
1150 hr = IDirect3DDevice9_CreateTexture(p_d3ddev,
1151 p_vout->render.i_width,
1152 p_vout->render.i_height,
1154 D3DUSAGE_RENDERTARGET,
1155 p_vout->p_sys->bbFormat,
1161 msg_Err(p_vout, "Failed to create texture. (hr=0x%lx)", hr);
1162 return VLC_EGENERIC;
1166 ** Create a vertex buffer for use when rendering scene
1168 hr = IDirect3DDevice9_CreateVertexBuffer(p_d3ddev,
1169 sizeof(CUSTOMVERTEX)*4,
1170 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
1171 D3DFVF_CUSTOMVERTEX,
1177 msg_Err(p_vout, "Failed to create vertex buffer. (hr=0x%lx)", hr);
1178 IDirect3DTexture9_Release(p_d3dtex);
1179 return VLC_EGENERIC;
1182 p_vout->p_sys->p_d3dtex = p_d3dtex;
1183 p_vout->p_sys->p_d3dvtc = p_d3dvtc;
1185 // Texture coordinates outside the range [0.0, 1.0] are set
1186 // to the texture color at 0.0 or 1.0, respectively.
1187 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1188 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1190 // Set linear filtering quality
1191 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
1192 IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
1194 // set maximum ambient light
1195 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
1198 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_CULLMODE, D3DCULL_NONE);
1200 // Turn off the zbuffer
1201 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ZENABLE, D3DZB_FALSE);
1204 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_LIGHTING, FALSE);
1207 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DITHERENABLE, TRUE);
1210 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_STENCILENABLE, FALSE);
1213 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
1214 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
1215 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
1216 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHATESTENABLE,TRUE);
1217 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAREF, 0x10);
1218 IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER);
1220 // Set texture states
1221 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE);
1222 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
1223 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
1225 // turn off alpha operation
1226 IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
1228 msg_Dbg( p_vout, "Direct3D scene created successfully");
1233 /*****************************************************************************
1234 * Direct3DVoutReleaseScene
1235 *****************************************************************************/
1236 static void Direct3DVoutReleaseScene( vout_thread_t *p_vout )
1238 LPDIRECT3DTEXTURE9 p_d3dtex = p_vout->p_sys->p_d3dtex;
1239 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1243 IDirect3DVertexBuffer9_Release(p_d3dvtc);
1244 p_vout->p_sys->p_d3dvtc = NULL;
1249 IDirect3DTexture9_Release(p_d3dtex);
1250 p_vout->p_sys->p_d3dtex = NULL;
1252 msg_Dbg( p_vout, "Direct3D scene released successfully");
1255 /*****************************************************************************
1256 * Render: copy picture surface into a texture and render into a scene
1257 *****************************************************************************
1258 * This function is intented for higher end 3D cards, with pixel shader support
1259 * and at least 64 MB of video RAM.
1260 *****************************************************************************/
1261 static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic )
1263 LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
1264 LPDIRECT3DTEXTURE9 p_d3dtex;
1265 LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
1266 LPDIRECT3DSURFACE9 p_d3dsrc, p_d3ddest;
1267 CUSTOMVERTEX *p_vertices;
1269 float f_width, f_height;
1271 // check if device is still available
1272 hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
1275 if( (D3DERR_DEVICENOTRESET != hr)
1276 || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout)) )
1278 // device is not usable at present (lost device, out of video mem ?)
1282 p_d3dtex = p_vout->p_sys->p_d3dtex;
1283 p_d3dvtc = p_vout->p_sys->p_d3dvtc;
1285 /* Clear the backbuffer and the zbuffer */
1286 hr = IDirect3DDevice9_Clear( p_d3ddev, 0, NULL, D3DCLEAR_TARGET,
1287 D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0 );
1290 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1294 /* retrieve picture surface */
1295 p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
1296 if( NULL == p_d3dsrc )
1298 msg_Dbg( p_vout, "no surface to render ?");
1302 /* retrieve texture top-level surface */
1303 hr = IDirect3DTexture9_GetSurfaceLevel(p_d3dtex, 0, &p_d3ddest);
1306 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1310 /* Copy picture surface into texture surface, color space conversion happens here */
1311 hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, NULL, p_d3ddest, NULL, D3DTEXF_NONE);
1312 IDirect3DSurface9_Release(p_d3ddest);
1315 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1319 /* Update the vertex buffer */
1320 hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (VOID **)(&p_vertices), D3DLOCK_DISCARD);
1323 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1327 /* Setup vertices */
1328 f_width = (float)(p_vout->output.i_width);
1329 f_height = (float)(p_vout->output.i_height);
1331 /* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */
1332 /* http://www.sjbrown.co.uk/2003/05/01/fix-directx-rasterisation/ */
1333 p_vertices[0].x = -0.5f; // left
1334 p_vertices[0].y = -0.5f; // top
1335 p_vertices[0].z = 0.0f;
1336 p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1337 p_vertices[0].rhw = 1.0f;
1338 p_vertices[0].tu = 0.0f;
1339 p_vertices[0].tv = 0.0f;
1341 p_vertices[1].x = f_width - 0.5f; // right
1342 p_vertices[1].y = -0.5f; // top
1343 p_vertices[1].z = 0.0f;
1344 p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1345 p_vertices[1].rhw = 1.0f;
1346 p_vertices[1].tu = 1.0f;
1347 p_vertices[1].tv = 0.0f;
1349 p_vertices[2].x = f_width - 0.5f; // right
1350 p_vertices[2].y = f_height - 0.5f; // bottom
1351 p_vertices[2].z = 0.0f;
1352 p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1353 p_vertices[2].rhw = 1.0f;
1354 p_vertices[2].tu = 1.0f;
1355 p_vertices[2].tv = 1.0f;
1357 p_vertices[3].x = -0.5f; // left
1358 p_vertices[3].y = f_height - 0.5f; // bottom
1359 p_vertices[3].z = 0.0f;
1360 p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
1361 p_vertices[3].rhw = 1.0f;
1362 p_vertices[3].tu = 0.0f;
1363 p_vertices[3].tv = 1.0f;
1365 hr= IDirect3DVertexBuffer9_Unlock(p_d3dvtc);
1368 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1373 hr = IDirect3DDevice9_BeginScene(p_d3ddev);
1376 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1380 // Setup our texture. Using textures introduces the texture stage states,
1381 // which govern how textures get blended together (in the case of multiple
1382 // textures) and lighting information. In this case, we are modulating
1383 // (blending) our texture with the diffuse color of the vertices.
1384 hr = IDirect3DDevice9_SetTexture(p_d3ddev, 0, (LPDIRECT3DBASETEXTURE9)p_d3dtex);
1387 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1388 IDirect3DDevice9_EndScene(p_d3ddev);
1392 // Render the vertex buffer contents
1393 hr = IDirect3DDevice9_SetStreamSource(p_d3ddev, 0, p_d3dvtc, 0, sizeof(CUSTOMVERTEX));
1396 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1397 IDirect3DDevice9_EndScene(p_d3ddev);
1401 // we use FVF instead of vertex shader
1402 hr = IDirect3DDevice9_SetFVF(p_d3ddev, D3DFVF_CUSTOMVERTEX);
1405 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1406 IDirect3DDevice9_EndScene(p_d3ddev);
1411 hr = IDirect3DDevice9_DrawPrimitive(p_d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
1414 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
1415 IDirect3DDevice9_EndScene(p_d3ddev);
1420 hr = IDirect3DDevice9_EndScene(p_d3ddev);
1423 msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);