qt: playlist: use item title if available
[vlc.git] / modules / video_chroma / d3d9_fmt.c
blobd8c21fc41fa8ab05a9398ec4e613caa72b0eae19
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 *****************************************************************************/
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #include <assert.h>
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>
34 #include <initguid.h>
35 #include "d3d9_fmt.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;
48 typedef struct {
49 void *opaque;
50 libvlc_video_output_cleanup_cb cleanupDeviceCb;
52 d3d9_decoder_device_t dec_device;
53 } d3d9_decoder_device;
55 /**
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;
71 #if !VLC_WINSTORE_APP
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);
82 /* */
83 HRESULT hr;
84 if (dec_dev->hd3d.use_ex){
85 hr = IDirect3DDevice9Ex_ResetEx(dec_dev->d3ddev.devex, &d3dpp, NULL);
86 } else {
87 hr = IDirect3DDevice9_Reset(dec_dev->d3ddev.dev, &d3dpp);
89 if (FAILED(hr)) {
90 msg_Err(o, "IDirect3DDevice9_Reset failed! (hr=0x%lX)", hr);
91 return VLC_EGENERIC;
93 return VLC_SUCCESS;
96 static void D3D9_Destroy(d3d9_handle_t *hd3d)
98 if (hd3d->obj)
100 IDirect3D9_Release(hd3d->obj);
101 hd3d->obj = NULL;
103 if (hd3d->hdll)
105 FreeLibrary(hd3d->hdll);
106 hd3d->hdll = NULL;
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"));
116 if (!hd3d->hdll) {
117 msg_Warn(o, "cannot load d3d9.dll, aborting");
118 return VLC_EGENERIC;
121 IDirect3D9 *(WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
122 OurDirect3DCreate9 =
123 (void *)GetProcAddress(hd3d->hdll, "Direct3DCreate9");
124 if (!OurDirect3DCreate9) {
125 msg_Err(o, "Cannot locate reference to Direct3DCreate9 ABI in DLL");
126 goto error;
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);
137 if(!FAILED(hr)) {
138 msg_Dbg(o, "Using Direct3D9 Extended API!");
139 hd3d->use_ex = true;
143 if (!hd3d->obj)
145 hd3d->obj = OurDirect3DCreate9(D3D_SDK_VERSION);
146 if (!hd3d->obj) {
147 msg_Err(o, "Could not create Direct3D9 instance.");
148 goto error;
151 return VLC_SUCCESS;
152 error:
153 D3D9_Destroy( hd3d );
154 return VLC_EGENERIC;
157 static void D3D9_CloneExternal(d3d9_handle_t *hd3d, IDirect3D9 *dev)
159 hd3d->obj = dev;
160 IDirect3D9_AddRef( hd3d->obj );
161 hd3d->hdll = NULL;
163 void *pv = NULL;
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)
171 HRESULT hr;
172 D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
174 d3d9_decoder_device *sys = vlc_obj_malloc(o, sizeof(*sys));
175 if (unlikely(sys==NULL))
176 return NULL;
178 d3d9_device_t *out = &sys->dec_device.d3ddev;
179 d3d9_handle_t *hd3d = &sys->dec_device.hd3d;
181 int AdapterToUse;
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 ))
198 goto error;
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" );
211 goto error;
213 /* find the best adapter to use, not based on the HWND used */
214 AdapterToUse = -1;
216 else
217 goto error;
219 if (AdapterToUse == -1)
221 AdapterToUse = D3DADAPTER_DEFAULT;
222 #ifndef NDEBUG
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;
232 break;
235 #endif
239 ** Get device capabilities
241 ZeroMemory(&out->caps, sizeof(out->caps));
242 hr = IDirect3D9_GetDeviceCaps(hd3d->obj, AdapterToUse, DeviceType, &out->caps);
243 if (FAILED(hr)) {
244 msg_Err(o, "Could not read adapter capabilities. (hr=0x%lX)", hr);
245 goto error;
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.");
252 goto error;
255 out->adapterId = AdapterToUse;
257 D3DPRESENT_PARAMETERS d3dpp;
258 FillPresentationParameters(&d3dpp);
260 /* */
261 if (FAILED(IDirect3D9_GetAdapterIdentifier(hd3d->obj, AdapterToUse,0, &out->identifier))) {
262 msg_Warn(o, "IDirect3D9_GetAdapterIdentifier failed");
263 } else {
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];
279 if (hd3d->use_ex)
280 hr = IDirect3D9Ex_CreateDeviceEx(hd3d->objex, AdapterToUse,
281 DeviceType, NULL,
282 creationFlags,
283 &d3dpp, NULL, &out->devex);
284 else
285 hr = IDirect3D9_CreateDevice(hd3d->obj, AdapterToUse,
286 DeviceType, NULL,
287 creationFlags,
288 &d3dpp, &out->dev);
289 if (SUCCEEDED(hr))
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);
299 error:
300 if ( sys->cleanupDeviceCb )
301 sys->cleanupDeviceCb( sys->opaque );
302 vlc_obj_free( o, sys );
303 return NULL;
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 = {
317 NULL,
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);
324 free(pic_ctx);
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))
331 return NULL;
332 *pic_ctx = *D3D9_PICCONTEXT_FROM_PICCTX(ctx);
333 vlc_video_context_Hold(pic_ctx->s.vctx);
334 AcquireD3D9PictureSys(&pic_ctx->picsys);
335 return &pic_ctx->s;