1 /*****************************************************************************
2 * d3d9_fmt.c : D3D9 helper calls
3 *****************************************************************************
4 * Copyright © 2017 VLC authors, VideoLAN and VideoLabs
6 * Authors: Steve Lhomme <robux4@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
28 #include <vlc/libvlc.h>
29 #include <vlc/libvlc_picture.h>
30 #include <vlc/libvlc_media.h>
31 #include <vlc/libvlc_renderer_discoverer.h>
32 #include <vlc/libvlc_media_player.h>
37 #define D3D9_PICCONTEXT_FROM_PICCTX(pic_ctx) \
38 container_of((pic_ctx), struct d3d9_pic_context, s)
40 picture_sys_d3d9_t
*ActiveD3D9PictureSys(picture_t
*pic
)
42 assert(pic
->context
!= NULL
);
43 assert(pic
->p_sys
== NULL
);
44 struct d3d9_pic_context
*pic_ctx
= D3D9_PICCONTEXT_FROM_PICCTX(pic
->context
);
45 return &pic_ctx
->picsys
;
50 libvlc_video_output_cleanup_cb cleanupDeviceCb
;
52 d3d9_decoder_device_t dec_device
;
53 } d3d9_decoder_device
;
56 * It setup vout_display_sys_t::d3dpp and vout_display_sys_t::rect_display
57 * from the default adapter.
59 static void FillPresentationParameters(D3DPRESENT_PARAMETERS
*d3dpp
)
61 /* Set up the structure used to create the D3DDevice. */
62 ZeroMemory(d3dpp
, sizeof(D3DPRESENT_PARAMETERS
));
63 d3dpp
->Flags
= D3DPRESENTFLAG_VIDEO
;
64 d3dpp
->Windowed
= TRUE
;
65 d3dpp
->MultiSampleType
= D3DMULTISAMPLE_NONE
;
66 d3dpp
->PresentationInterval
= D3DPRESENT_INTERVAL_DEFAULT
;
67 d3dpp
->EnableAutoDepthStencil
= FALSE
;
68 d3dpp
->hDeviceWindow
= NULL
;
69 d3dpp
->SwapEffect
= D3DSWAPEFFECT_COPY
;
70 d3dpp
->BackBufferCount
= 1;
72 d3dpp
->BackBufferWidth
= GetSystemMetrics(SM_CXVIRTUALSCREEN
);
73 d3dpp
->BackBufferHeight
= GetSystemMetrics(SM_CYVIRTUALSCREEN
);
74 #endif // VLC_WINSTORE_APP
77 int D3D9_ResetDevice(vlc_object_t
*o
, d3d9_decoder_device_t
*dec_dev
)
79 D3DPRESENT_PARAMETERS d3dpp
;
80 FillPresentationParameters(&d3dpp
);
84 if (dec_dev
->hd3d
.use_ex
){
85 hr
= IDirect3DDevice9Ex_ResetEx(dec_dev
->d3ddev
.devex
, &d3dpp
, NULL
);
87 hr
= IDirect3DDevice9_Reset(dec_dev
->d3ddev
.dev
, &d3dpp
);
90 msg_Err(o
, "IDirect3DDevice9_Reset failed! (hr=0x%lX)", hr
);
96 static void D3D9_Destroy(d3d9_handle_t
*hd3d
)
100 IDirect3D9_Release(hd3d
->obj
);
105 FreeLibrary(hd3d
->hdll
);
111 * It initializes an instance of Direct3D9
113 static int D3D9_Create(vlc_object_t
*o
, d3d9_handle_t
*hd3d
)
115 hd3d
->hdll
= LoadLibrary(TEXT("D3D9.DLL"));
117 msg_Warn(o
, "cannot load d3d9.dll, aborting");
121 IDirect3D9
*(WINAPI
*OurDirect3DCreate9
)(UINT SDKVersion
);
123 (void *)GetProcAddress(hd3d
->hdll
, "Direct3DCreate9");
124 if (!OurDirect3DCreate9
) {
125 msg_Err(o
, "Cannot locate reference to Direct3DCreate9 ABI in DLL");
129 HRESULT (WINAPI
*OurDirect3DCreate9Ex
)(UINT SDKVersion
, IDirect3D9Ex
**ppD3D
);
130 OurDirect3DCreate9Ex
=
131 (void *)GetProcAddress(hd3d
->hdll
, "Direct3DCreate9Ex");
133 /* Create the D3D object. */
134 hd3d
->use_ex
= false;
135 if (OurDirect3DCreate9Ex
) {
136 HRESULT hr
= OurDirect3DCreate9Ex(D3D_SDK_VERSION
, &hd3d
->objex
);
138 msg_Dbg(o
, "Using Direct3D9 Extended API!");
145 hd3d
->obj
= OurDirect3DCreate9(D3D_SDK_VERSION
);
147 msg_Err(o
, "Could not create Direct3D9 instance.");
153 D3D9_Destroy( hd3d
);
157 static void D3D9_CloneExternal(d3d9_handle_t
*hd3d
, IDirect3D9
*dev
)
160 IDirect3D9_AddRef( hd3d
->obj
);
164 hd3d
->use_ex
= SUCCEEDED(IDirect3D9_QueryInterface(dev
, &IID_IDirect3D9Ex
, &pv
));
165 if (hd3d
->use_ex
&& pv
)
166 IDirect3D9Ex_Release((IDirect3D9Ex
*) pv
);
169 d3d9_decoder_device_t
*(D3D9_CreateDevice
)(vlc_object_t
*o
)
172 D3DDEVTYPE DeviceType
= D3DDEVTYPE_HAL
;
174 d3d9_decoder_device
*sys
= vlc_obj_malloc(o
, sizeof(*sys
));
175 if (unlikely(sys
==NULL
))
178 d3d9_device_t
*out
= &sys
->dec_device
.d3ddev
;
179 d3d9_handle_t
*hd3d
= &sys
->dec_device
.hd3d
;
183 sys
->cleanupDeviceCb
= NULL
;
184 libvlc_video_engine_t engineType
= var_InheritInteger( o
, "vout-cb-type" );
185 libvlc_video_output_setup_cb setupDeviceCb
= NULL
;
186 if (engineType
== libvlc_video_engine_d3d9
)
187 setupDeviceCb
= var_InheritAddress( o
, "vout-cb-setup" );
188 if ( setupDeviceCb
!= NULL
)
190 /* external rendering */
191 libvlc_video_setup_device_info_t extern_out
= { .d3d9
.adapter
= -1 };
192 sys
->opaque
= var_InheritAddress( o
, "vout-cb-opaque" );
193 sys
->cleanupDeviceCb
= var_InheritAddress( o
, "vout-cb-cleanup" );
194 libvlc_video_setup_device_cfg_t cfg
= {
195 .hardware_decoding
= true, /* ignored anyway */
197 if (!setupDeviceCb( &sys
->opaque
, &cfg
, &extern_out
))
200 D3D9_CloneExternal( hd3d
, (IDirect3D9
*) extern_out
.d3d9
.device
);
201 AdapterToUse
= extern_out
.d3d9
.adapter
;
203 else if ( engineType
== libvlc_video_engine_disable
||
204 engineType
== libvlc_video_engine_d3d9
||
205 engineType
== libvlc_video_engine_opengl
)
207 /* internal rendering */
208 if (D3D9_Create(o
, hd3d
) != VLC_SUCCESS
)
210 msg_Err( o
, "Direct3D9 could not be initialized" );
213 /* find the best adapter to use, not based on the HWND used */
219 if (AdapterToUse
== -1)
221 AdapterToUse
= D3DADAPTER_DEFAULT
;
223 // Check for 'NVIDIA PerfHUD' adapter
224 // If it is present, override default settings for performance debugging
225 // see https://developer.nvidia.com/nvidia-perfhud up to Win7
226 for (UINT Adapter
=0; Adapter
< IDirect3D9_GetAdapterCount(hd3d
->obj
); ++Adapter
) {
227 D3DADAPTER_IDENTIFIER9 Identifier
;
228 hr
= IDirect3D9_GetAdapterIdentifier(hd3d
->obj
, Adapter
, 0, &Identifier
);
229 if (SUCCEEDED(hr
) && strstr(Identifier
.Description
,"PerfHUD") != 0) {
230 AdapterToUse
= Adapter
;
231 DeviceType
= D3DDEVTYPE_REF
;
239 ** Get device capabilities
241 ZeroMemory(&out
->caps
, sizeof(out
->caps
));
242 hr
= IDirect3D9_GetDeviceCaps(hd3d
->obj
, AdapterToUse
, DeviceType
, &out
->caps
);
244 msg_Err(o
, "Could not read adapter capabilities. (hr=0x%lX)", hr
);
247 msg_Dbg(o
, "D3D9 device caps 0x%lX / 0x%lX", out
->caps
.DevCaps
, out
->caps
.DevCaps2
);
249 /* TODO: need to test device capabilities and select the right render function */
250 if (!(out
->caps
.DevCaps2
& D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES
)) {
251 msg_Err(o
, "Device does not support stretching from textures.");
255 out
->adapterId
= AdapterToUse
;
257 D3DPRESENT_PARAMETERS d3dpp
;
258 FillPresentationParameters(&d3dpp
);
261 if (FAILED(IDirect3D9_GetAdapterIdentifier(hd3d
->obj
, AdapterToUse
,0, &out
->identifier
))) {
262 msg_Warn(o
, "IDirect3D9_GetAdapterIdentifier failed");
264 msg_Dbg(o
, "Direct3d9 Device: %s %lx %lx %lx", out
->identifier
.Description
,
265 out
->identifier
.VendorId
, out
->identifier
.DeviceId
, out
->identifier
.Revision
);
268 DWORD thread_modes
[] = { D3DCREATE_MULTITHREADED
, 0 };
269 DWORD vertex_modes
[] = { D3DCREATE_HARDWARE_VERTEXPROCESSING
| D3DCREATE_PUREDEVICE
,
270 D3DCREATE_HARDWARE_VERTEXPROCESSING
,
271 D3DCREATE_MIXED_VERTEXPROCESSING
,
272 D3DCREATE_SOFTWARE_VERTEXPROCESSING
};
274 for (size_t t
= 0; t
< ARRAY_SIZE(thread_modes
); t
++)
276 for (size_t v
= 0; v
< ARRAY_SIZE(vertex_modes
); v
++)
278 DWORD creationFlags
= thread_modes
[t
] | vertex_modes
[v
];
280 hr
= IDirect3D9Ex_CreateDeviceEx(hd3d
->objex
, AdapterToUse
,
283 &d3dpp
, NULL
, &out
->devex
);
285 hr
= IDirect3D9_CreateDevice(hd3d
->obj
, AdapterToUse
,
291 return &sys
->dec_device
;
296 msg_Err(o
, "failed to create the D3D9%s device %d/%d. (hr=0x%lX)",
297 hd3d
->use_ex
?"Ex":"", AdapterToUse
, DeviceType
, hr
);
300 if ( sys
->cleanupDeviceCb
)
301 sys
->cleanupDeviceCb( sys
->opaque
);
302 vlc_obj_free( o
, sys
);
306 void D3D9_ReleaseDevice(d3d9_decoder_device_t
*dec_dev
)
308 d3d9_decoder_device
*sys
= container_of(dec_dev
, d3d9_decoder_device
, dec_device
);
309 if (dec_dev
->d3ddev
.dev
)
310 IDirect3DDevice9_Release(dec_dev
->d3ddev
.dev
);
311 D3D9_Destroy( &dec_dev
->hd3d
);
312 if ( sys
->cleanupDeviceCb
)
313 sys
->cleanupDeviceCb( sys
->opaque
);
316 const struct vlc_video_context_operations d3d9_vctx_ops
= {
320 void d3d9_pic_context_destroy(picture_context_t
*ctx
)
322 struct d3d9_pic_context
*pic_ctx
= D3D9_PICCONTEXT_FROM_PICCTX(ctx
);
323 ReleaseD3D9PictureSys(&pic_ctx
->picsys
);
327 picture_context_t
*d3d9_pic_context_copy(picture_context_t
*ctx
)
329 struct d3d9_pic_context
*pic_ctx
= calloc(1, sizeof(*pic_ctx
));
330 if (unlikely(pic_ctx
==NULL
))
332 *pic_ctx
= *D3D9_PICCONTEXT_FROM_PICCTX(ctx
);
333 vlc_video_context_Hold(pic_ctx
->s
.vctx
);
334 AcquireD3D9PictureSys(&pic_ctx
->picsys
);