1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2020
6 * All rights reserved
7 *
8 * This file is part of GPAC / DirectX audio and video render module
9 *
10 * GPAC is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * GPAC is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; see the file COPYING. If not, write to
22 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26
27 #include "dx_hw.h"
28
29 #include <gpac/user.h>
30
31
32 #ifdef _WIN32_WCE
33 #ifdef GPAC_USE_GLES1X
34 #endif
35 #elif defined(GPAC_USE_GLES2)
36 #include <GLES2/gl2.h>
37 #include <GLES2/gl2ext.h>
38
39 //# pragma comment(lib, "libGLESv2")
40 # pragma comment(lib, "libEGL")
41
42
43 #else
44 #include <GL/gl.h>
45
46 # pragma comment(lib, "opengl32")
47
48
49 #endif
50
51
52 #define DDCONTEXT DDContext *dd = (DDContext *)dr->opaque;
53
54
55
56 #ifndef GPAC_DISABLE_3D
57
58 #define WGL_DRAW_TO_WINDOW_ARB 0x2001
59 #define WGL_PIXEL_TYPE_ARB 0x2013
60 #define WGL_RED_BITS_ARB 0x2015
61 #define WGL_GREEN_BITS_ARB 0x2017
62 #define WGL_BLUE_BITS_ARB 0x2019
63 #define WGL_ALPHA_BITS_ARB 0x201B
64 #define WGL_TEXTURE_FORMAT_ARB 0x2072
65 #define WGL_TEXTURE_TARGET_ARB 0x2073
66 #define WGL_TEXTURE_RGB_ARB 0x2075
67
68 #define WGL_TEXTURE_RGBA_ARB 0x2076
69 #define WGL_NO_TEXTURE_ARB 0x2077
70 #define WGL_TEXTURE_2D_ARB 0x207A
71 #define WGL_SUPPORT_OPENGL_ARB 0x2010
72 #define WGL_DOUBLE_BUFFER_ARB 0x2011
73 #define WGL_DRAW_TO_PBUFFER_ARB 0x202D
74 #define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071
75 #define WGL_COLOR_BITS_ARB 0x2014
76 #define WGL_DEPTH_BITS_ARB 0x2022
77 #define WGL_STENCIL_BITS_ARB 0x2023
78 #define WGL_ACCELERATION_ARB 0x2003
79 #define WGL_GENERIC_ACCELERATION_ARB 0x2026
80 #define WGL_FULL_ACCELERATION_ARB 0x2027
81 #define WGL_TYPE_RGBA_ARB 0x202B
82
83 typedef Bool (APIENTRY *CHOOSEPFFORMATARB)(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
84 static CHOOSEPFFORMATARB wglChoosePixelFormatARB = NULL;
85
86 typedef Bool (APIENTRY *GETPIXELFORMATATTRIBIV)(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int* piAttributes, int *piValues);
87 static GETPIXELFORMATATTRIBIV wglGetPixelFormatAttribivARB = NULL;
88
89
90 typedef BOOL (APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int );
91 PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = NULL;
92
93 #endif
94
95
RestoreWindow(DDContext * dd)96 static void RestoreWindow(DDContext *dd)
97 {
98 if (!dd->NeedRestore) return;
99 dd->NeedRestore = GF_FALSE;
100
101 #ifndef GPAC_DISABLE_3D
102 if (dd->output_3d) {
103 #ifndef _WIN32_WCE
104 ChangeDisplaySettings(NULL,0);
105 #endif
106 } else
107 #endif
108
109 dd->pDD->lpVtbl->SetCooperativeLevel(dd->pDD, dd->cur_hwnd, DDSCL_NORMAL);
110 dd->NeedRestore = GF_FALSE;
111
112 // SetForegroundWindow(dd->cur_hwnd);
113 SetFocus(dd->cur_hwnd);
114 }
115
DestroyObjectsEx(DDContext * dd,Bool only_3d)116 void DestroyObjectsEx(DDContext *dd, Bool only_3d)
117 {
118 if (!only_3d) {
119 // RestoreWindow(dd);
120
121 SAFE_DD_RELEASE(dd->rgb_pool.pSurface);
122 memset(&dd->rgb_pool, 0, sizeof(DDSurface));
123 SAFE_DD_RELEASE(dd->yuv_pool.pSurface);
124 memset(&dd->yuv_pool, 0, sizeof(DDSurface));
125 dd->yuv_pool.is_yuv = GF_TRUE;
126
127 SAFE_DD_RELEASE(dd->pPrimary);
128 SAFE_DD_RELEASE(dd->pBack);
129 SAFE_DD_RELEASE(dd->pDD);
130 dd->ddraw_init = GF_FALSE;
131
132 #ifdef GPAC_DISABLE_3D
133 }
134 #else
135 }
136
137 /*delete openGL context*/
138 #if defined(GPAC_USE_GLES1X) || defined(GPAC_USE_GLES2)
139 if (dd->eglctx) eglDestroyContext(dd->egldpy, dd->eglctx);
140 dd->eglctx = NULL;
141 if (dd->surface) eglDestroySurface(dd->egldpy, dd->surface);
142 dd->surface = NULL;
143 if (dd->gl_HDC) {
144 if (dd->egldpy) eglTerminate(dd->egldpy);
145 ReleaseDC(dd->cur_hwnd, (HDC) dd->gl_HDC);
146 dd->gl_HDC = 0L;
147 dd->egldpy = NULL;
148 }
149 #elif !defined(_WIN32_WCE)
150
151 if (dd->pb_HRC) {
152 wglMakeCurrent(dd->pb_HDC, NULL);
153 wglDeleteContext(dd->pb_HRC);
154 dd->pb_HRC = NULL;
155 }
156 if (dd->pb_HDC) {
157 // wglReleasePbufferDCARB(dd->pbuffer, dd->pb_HDC);
158 ReleaseDC(dd->bound_hwnd, dd->pb_HDC);
159 dd->pb_HDC = NULL;
160 }
161
162 if (dd->gl_HRC) {
163 //wglMakeCurrent(NULL, NULL);
164 wglDeleteContext(dd->gl_HRC);
165 dd->gl_HRC = NULL;
166 }
167 if (dd->gl_HDC) {
168 ReleaseDC(dd->bound_hwnd, dd->gl_HDC);
169 dd->gl_HDC = NULL;
170 }
171 #endif
172
173
174 #endif
175 }
176
DestroyObjects(DDContext * dd)177 void DestroyObjects(DDContext *dd)
178 {
179 DestroyObjectsEx(dd, GF_FALSE);
180 }
181
182 #ifndef GPAC_DISABLE_3D
183
DD_SetupOpenGL(GF_VideoOutput * dr,u32 offscreen_width,u32 offscreen_height)184 GF_Err DD_SetupOpenGL(GF_VideoOutput *dr, u32 offscreen_width, u32 offscreen_height)
185 {
186 #if defined(GPAC_USE_GLES1X) || defined(GPAC_USE_GLES2) || !defined(_WIN32_WCE)
187 const char *sOpt;
188 #endif
189 GF_Event evt;
190 Bool hw_reset = GF_FALSE;
191 DDCONTEXT
192
193 #if defined(GPAC_USE_GLES1X) || defined(GPAC_USE_GLES2)
194 EGLint major, minor;
195 EGLint n;
196 EGLConfig configs[1];
197 u32 nb_bits;
198 u32 i=0;
199 static int egl_atts[20];
200
201 sOpt = gf_opts_get_key("core", "gl-bits-comp");
202 nb_bits = sOpt ? atoi(sOpt) : 5;
203
204 egl_atts[i++] = EGL_RED_SIZE;
205 egl_atts[i++] = nb_bits;
206 egl_atts[i++] = EGL_GREEN_SIZE;
207 egl_atts[i++] = nb_bits;
208 egl_atts[i++] = EGL_BLUE_SIZE;
209 egl_atts[i++] = nb_bits;
210 /*alpha for compositeTexture*/
211 egl_atts[i++] = EGL_ALPHA_SIZE;
212 egl_atts[i++] = 1;
213 sOpt = gf_opts_get_key("core", "gl-bits-depth");
214 nb_bits = sOpt ? atoi(sOpt) : 5;
215 egl_atts[i++] = EGL_DEPTH_SIZE;
216 egl_atts[i++] = nb_bits;
217 egl_atts[i++] = EGL_STENCIL_SIZE;
218 egl_atts[i++] = EGL_DONT_CARE;
219
220 egl_atts[i++] = EGL_RENDERABLE_TYPE;
221 egl_atts[i++] = EGL_OPENGL_ES2_BIT;
222
223 egl_atts[i++] = EGL_NONE;
224
225
226 /*already setup*/
227 DestroyObjects(dd);
228 dd->gl_HDC = (NativeDisplayType) GetDC(dd->cur_hwnd);
229 dd->egldpy = eglGetDisplay(/*dd->gl_HDC*/ EGL_DEFAULT_DISPLAY);
230 if (!eglInitialize(dd->egldpy, &major, &minor)) return GF_IO_ERR;
231 if (!eglChooseConfig(dd->egldpy, egl_atts, configs, 1, &n)) return GF_IO_ERR;
232 dd->eglconfig = configs[0];
233 dd->surface = eglCreateWindowSurface(dd->egldpy, dd->eglconfig, dd->cur_hwnd, 0);
234 if (!dd->surface) return GF_IO_ERR;
235
236 #ifdef GPAC_USE_GLES2
237
238 i=0;
239 egl_atts[i++] = EGL_CONTEXT_CLIENT_VERSION;
240 egl_atts[i++] = 2;
241 egl_atts[i++] = EGL_NONE;
242
243 eglBindAPI(EGL_OPENGL_ES_API);
244 dd->eglctx = eglCreateContext(dd->egldpy, dd->eglconfig, NULL, egl_atts);
245 #else
246 dd->eglctx = eglCreateContext(dd->egldpy, dd->eglconfig, NULL, NULL);
247 #endif
248
249 if (!dd->eglctx) {
250 eglDestroySurface(dd->egldpy, dd->surface);
251 dd->surface = 0L;
252 return GF_IO_ERR;
253 }
254 if (!eglMakeCurrent(dd->egldpy, dd->surface, dd->surface, dd->eglctx)) {
255 eglDestroyContext(dd->egldpy, dd->eglctx);
256 dd->eglctx = 0L;
257 eglDestroySurface(dd->egldpy, dd->surface);
258 dd->surface = 0L;
259 return GF_IO_ERR;
260 }
261 #elif !defined(_WIN32_WCE)
262 PIXELFORMATDESCRIPTOR pfd;
263 s32 pixelformat;
264 HWND highbpp_hwnd = NULL;
265 HWND target_hwnd;
266 int bits_depth = 16;
267 u32 i;
268 Bool use_double_buffer;
269
270 /*already setup*/
271 target_hwnd = dd->cur_hwnd;
272 if ((dd->bound_hwnd == target_hwnd) && dd->gl_HRC)
273 goto exit;
274
275 hw_reset = GF_TRUE;
276 dd->bound_hwnd = target_hwnd;
277
278 /*cleanup*/
279 DestroyObjectsEx(dd, dd->output_3d ? GF_FALSE : GF_TRUE);
280
281 //first time we init GL: create a dummy window to select pixel format for high bpp - we must do this because
282 //- we must get a valid GL context to query the extensions for bpp > 8 (regular choosePixelFormat does not work for them)
283 //- we must call SetPixelFormat to create the GL context
284 //- it is not possible to call several time SetPixelFormat on the same window with different PF properties ...
285 if (!dd->mode_high_bpp) {
286 sOpt = gf_opts_get_key("core", "gl-bits-comp");
287 if (!sOpt) {
288 gf_opts_set_key("core", "gl-bits-comp", "8");
289 dd->bpp = 8;
290 } else {
291 dd->bpp = atoi(sOpt);
292 }
293 if (dd->bpp > 8) {
294 #ifdef UNICODE
295 highbpp_hwnd = CreateWindow(L"GPAC DirectDraw Output", L"dummy", WS_POPUP, 0, 0, 128, 128, NULL, NULL, NULL /* GetModuleHandle("gm_dx_hw.dll")*/, NULL);
296 #else
297 highbpp_hwnd = CreateWindow("GPAC DirectDraw Output", "dummy", WS_POPUP, 0, 0, 128, 128, NULL, NULL, NULL /* GetModuleHandle("gm_dx_hw.dll")*/, NULL);
298 #endif
299 dd->gl_HDC = GetDC(highbpp_hwnd);
300
301 memset(&pfd, 0, sizeof(pfd));
302 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
303 pfd.nVersion = 1;
304 pfd.dwFlags = PFD_SUPPORT_OPENGL;
305 if ( (pixelformat = ChoosePixelFormat(dd->gl_HDC, &pfd)) == FALSE ) return GF_IO_ERR;
306
307 if (SetPixelFormat(dd->gl_HDC, pixelformat, &pfd) == FALSE) {
308 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[DX GL] Cannot select pixel format: error %d- disabling GL\n", GetLastError() ));
309 return GF_IO_ERR;
310 }
311 dd->gl_HRC = wglCreateContext(dd->gl_HDC);
312 if (!dd->gl_HRC) return GF_IO_ERR;
313
314 HGLRC cur = wglGetCurrentContext();
315 if (cur) wglShareLists(cur, dd->gl_HRC);
316
317 wglMakeCurrent(dd->gl_HDC, dd->gl_HRC);
318 wglChoosePixelFormatARB = (CHOOSEPFFORMATARB) wglGetProcAddress("wglChoosePixelFormatARB");
319 wglGetPixelFormatAttribivARB = (GETPIXELFORMATATTRIBIV) wglGetProcAddress("wglGetPixelFormatAttribivARB");
320
321 wglMakeCurrent(NULL, NULL);
322 wglDeleteContext(dd->gl_HRC);
323 dd->gl_HRC = NULL;
324 ReleaseDC(highbpp_hwnd, dd->gl_HDC);
325 DestroyWindow(highbpp_hwnd);
326
327
328 dd->mode_high_bpp = wglChoosePixelFormatARB ? 1 : 2;
329 } else {
330 dd->mode_high_bpp = 2;
331 }
332 }
333
334 dd->gl_HDC = GetDC(dd->bound_hwnd);
335 if (!dd->gl_HDC) return GF_IO_ERR;
336
337 use_double_buffer = GF_FALSE;
338 if (dd->gl_double_buffer ) {
339 use_double_buffer = dd->gl_double_buffer;
340 } else {
341 sOpt = gf_opts_get_key("core", "gl-doublebuf");
342 if (!sOpt || !strcmp(sOpt, "yes")) use_double_buffer = GF_TRUE;
343 }
344
345 sOpt = gf_opts_get_key("core", "gl-bits-depth");
346 if (sOpt) bits_depth = atoi(sOpt);
347
348 memset(&pfd, 0, sizeof(pfd));
349 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
350 pfd.nVersion = 1;
351
352 if (dd->mode_high_bpp == 1) {
353 int pformats[200];
354 u32 nbformats=0;
355 Bool found = GF_FALSE;
356
357 int hdcAttributes[] = {
358 WGL_SUPPORT_OPENGL_ARB, TRUE,
359 WGL_DRAW_TO_WINDOW_ARB, (dd->bound_hwnd != dd->fs_hwnd) ? TRUE : FALSE,
360 WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
361 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
362 WGL_RED_BITS_ARB, dd->bpp,
363 WGL_GREEN_BITS_ARB, dd->bpp,
364 WGL_BLUE_BITS_ARB, dd->bpp,
365 WGL_ALPHA_BITS_ARB, (dd->bpp==10) ? 2 : 0,
366 WGL_DEPTH_BITS_ARB, bits_depth,
367 WGL_DOUBLE_BUFFER_ARB, use_double_buffer ? TRUE : FALSE,
368 0,0
369 };
370
371 wglChoosePixelFormatARB(dd->gl_HDC, hdcAttributes, NULL, 200, pformats, &nbformats);
372
373 for (i=0; i<nbformats; i++) {
374 if (SetPixelFormat(dd->gl_HDC, pformats[i], &pfd) != FALSE) {
375 found = GF_TRUE;
376 break;
377 }
378 }
379 if (!found) {
380 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[DX GL] Cannot select pixel format: error %d - disabling high color res GL and retrying\n", GetLastError() ));
381 dd->mode_high_bpp = 2;
382 return DD_SetupOpenGL(dr, offscreen_width, offscreen_height);
383 }
384
385 dr->max_screen_bpp = dd->bpp;
386
387 if (wglGetPixelFormatAttribivARB) {
388 int rb, gb, bb, att;
389 rb = gb = bb = 0;
390 att = WGL_RED_BITS_ARB;
391 wglGetPixelFormatAttribivARB(dd->gl_HDC, pformats[0], 0, 1, &att, &rb);
392 att = WGL_GREEN_BITS_ARB;
393 wglGetPixelFormatAttribivARB(dd->gl_HDC, pformats[0], 0, 1, &att, &gb);
394 att = WGL_BLUE_BITS_ARB;
395 wglGetPixelFormatAttribivARB(dd->gl_HDC, pformats[0], 0, 1, &att, &bb);
396
397 if ((rb != dd->bpp) || (gb != dd->bpp) || (bb != dd->bpp)) {
398 GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[DX GL] Asked for %d bits per pixel but got %d red %d green %d blue\n", dd->bpp, rb, gb, bb ));
399 } else {
400 GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[DX GL] Setup OpenGL bpp: %d red %d green %d blue\n", rb, gb, bb ));
401 }
402 }
403
404 } else {
405 pfd.dwFlags = PFD_SUPPORT_OPENGL;
406 if (dd->bound_hwnd != dd->fs_hwnd) pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
407
408 if (use_double_buffer) pfd.dwFlags |= PFD_DOUBLEBUFFER;
409 pfd.dwLayerMask = PFD_MAIN_PLANE;
410 pfd.iPixelType = PFD_TYPE_RGBA;
411 pfd.cColorBits = 32;
412 pfd.cDepthBits = bits_depth;
413 /*we need alpha support for composite textures...*/
414 pfd.cAlphaBits = 8;
415
416 if ( (pixelformat = ChoosePixelFormat(dd->gl_HDC, &pfd)) == FALSE ) return GF_IO_ERR;
417
418 if (SetPixelFormat(dd->gl_HDC, pixelformat, &pfd) == FALSE) {
419 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[DX GL] Cannot select pixel format: error %d- disabling GL\n", GetLastError() ));
420 return GF_IO_ERR;
421 }
422 }
423
424 dd->gl_HRC = wglCreateContext(dd->gl_HDC);
425 if (!dd->gl_HRC) return GF_IO_ERR;
426
427 if (!dd->glext_init) {
428 dd->glext_init = GF_TRUE;
429 wglMakeCurrent(dd->gl_HDC, dd->gl_HRC);
430 }
431
432 if (dd->disable_vsync) {
433 if (!wglSwapIntervalEXT) {
434 wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
435 }
436 if (wglSwapIntervalEXT) {
437 wglSwapIntervalEXT(0);
438 }
439 }
440
441 if (!wglMakeCurrent(dd->gl_HDC, dd->gl_HRC)) return GF_IO_ERR;
442
443 #endif
444
445 /*special care for Firefox: XUL and OpenGL do not go well together, there is a stack overflow in WM_PAINT
446 for our plugin window - avoid this by overriding the WindowProc once OpenGL is setup!!*/
447 if ((dd->bound_hwnd==dd->os_hwnd) && dd->orig_wnd_proc)
448 #ifdef _WIN64
449 SetWindowLongPtr(dd->os_hwnd, GWLP_WNDPROC, (LPARAM) DD_WindowProc);
450 #else
451 SetWindowLong(dd->os_hwnd, GWL_WNDPROC, (DWORD) DD_WindowProc);
452 #endif
453
454 #if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_GLES2) && !defined(_WIN32_WCE)
455 exit:
456 #endif
457
458 if (dd->output_3d) {
459 memset(&evt, 0, sizeof(GF_Event));
460 evt.type = GF_EVENT_VIDEO_SETUP;
461 evt.setup.hw_reset = hw_reset;
462 dr->on_event(dr->evt_cbk_hdl, &evt);
463 }
464 return GF_OK;
465 }
466
467 #endif
468
469
470
DD_Setup(GF_VideoOutput * dr,void * os_handle,void * os_display,u32 init_flags)471 GF_Err DD_Setup(GF_VideoOutput *dr, void *os_handle, void *os_display, u32 init_flags)
472 {
473 RECT rc;
474 DDCONTEXT
475 dd->os_hwnd = (HWND) os_handle;
476
477 DD_SetupWindow(dr, init_flags);
478 /*fatal error*/
479 if (!dd->os_hwnd) return GF_IO_ERR;
480 dd->cur_hwnd = dd->os_hwnd;
481
482 {
483 HDC hdc;
484 hdc = GetDC(dd->os_hwnd);
485 dr->dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
486 dr->dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
487 ReleaseDC(dd->os_hwnd, hdc);
488 }
489
490 #ifndef GPAC_DISABLE_3D
491 dd->output_3d = 0;
492 #endif
493 GetWindowRect(dd->cur_hwnd, &rc);
494
495 dd->disable_vsync = gf_opts_get_bool("core", "disable-vsync");
496
497 return GF_OK;
498 }
499
DD_Shutdown(GF_VideoOutput * dr)500 static void DD_Shutdown(GF_VideoOutput *dr)
501 {
502 DDCONTEXT
503
504 /*force destroy of opengl*/
505 DestroyObjects(dd);
506
507 DD_ShutdownWindow(dr);
508 }
509
DD_ShowTaskbar(Bool show)510 void DD_ShowTaskbar(Bool show)
511 {
512 #ifdef UNICODE
513 HWND tbwnd = FindWindow(L"Shell_TrayWnd", NULL);
514 HWND swnd = FindWindow(L"Button", NULL);
515 #else
516 HWND tbwnd = FindWindow("Shell_TrayWnd", NULL);
517 HWND swnd = FindWindow("Button", NULL);
518 #endif
519
520 if (tbwnd != NULL) {
521 ShowWindow(tbwnd, show ? SW_SHOW : SW_HIDE);
522 UpdateWindow(tbwnd);
523 }
524 if (swnd != NULL) {
525 // Vista
526 ShowWindow(swnd, show ? SW_SHOW : SW_HIDE);
527 UpdateWindow(swnd);
528 }
529 }
DD_SetFullScreen(GF_VideoOutput * dr,Bool bOn,u32 * outWidth,u32 * outHeight)530 static GF_Err DD_SetFullScreen(GF_VideoOutput *dr, Bool bOn, u32 *outWidth, u32 *outHeight)
531 {
532 GF_Err e;
533 DDCONTEXT;
534
535 if (bOn == dd->fullscreen) return GF_OK;
536 if (!dd->fs_hwnd) return GF_NOT_SUPPORTED;
537
538 dd->fullscreen = bOn;
539
540 if (!dd->width ||!dd->height) return GF_OK;
541
542 /*whenever changing card display mode relocate fastest YUV format for blit (since it depends
543 on the dest pixel format)*/
544 dd->yuv_init = GF_FALSE;
545 if (dd->fullscreen) {
546 dd->switch_res = gf_opts_get_bool("core", "switch-vres");
547 /*get current or best fitting mode*/
548 if (GetDisplayMode(dd) != GF_OK) return GF_IO_ERR;
549 }
550
551 if (dd->NeedRestore) RestoreWindow(dd);
552 /*destroy all objects*/
553 if (dd->os_hwnd!=dd->fs_hwnd) DestroyObjects(dd);
554
555 if (dd->timer) KillTimer(dd->cur_hwnd, dd->timer);
556 dd->timer = 0;
557 if (dd->os_hwnd != dd->fs_hwnd) {
558 ShowWindow(dd->cur_hwnd, SW_HIDE);
559 dd->cur_hwnd = dd->fullscreen ? dd->fs_hwnd : dd->os_hwnd;
560 ShowWindow(dd->cur_hwnd, SW_SHOW);
561 } else {
562 ShowWindow(dd->cur_hwnd, SW_HIDE);
563 SetWindowLong(dd->os_hwnd, GWL_STYLE, dd->fullscreen ? WS_POPUP : dd->backup_styles);
564 ShowWindow(dd->cur_hwnd, SW_SHOW);
565 }
566
567
568 dd->on_secondary_screen = GF_FALSE;
569 /*Setup FS*/
570 if (dd->fullscreen) {
571 int X = 0;
572 int Y = 0;
573 #if(WINVER >= 0x0500)
574 HMONITOR hMonitor;
575 MONITORINFOEX minfo;
576
577 DD_ShowTaskbar(GF_FALSE);
578
579 /*get monitor our windows is on*/
580 hMonitor = MonitorFromWindow(dd->os_hwnd, MONITOR_DEFAULTTONEAREST);
581 if (hMonitor) {
582 memset(&minfo, 0, sizeof(MONITORINFOEX));
583 minfo.cbSize = sizeof(MONITORINFOEX);
584 /*get monitor top-left for fullscreen switch, and adjust width and height*/
585 GetMonitorInfo(hMonitor, (LPMONITORINFO) &minfo);
586 dd->fs_width = minfo.rcWork.right - minfo.rcWork.left;
587 dd->fs_height = minfo.rcWork.bottom - minfo.rcWork.top;
588 X = minfo.rcWork.left;
589 Y = minfo.rcWork.top;
590
591 if (dd->fs_height+100 > dr->max_screen_height) {
592 dd->fs_height = dr->max_screen_height;
593 Y = 0;
594 }
595 if (!(minfo.dwFlags & MONITORINFOF_PRIMARY)) dd->on_secondary_screen = GF_TRUE;
596 }
597 #endif
598
599 SetWindowPos(dd->cur_hwnd, NULL, X, Y, dd->fs_width, dd->fs_height, SWP_SHOWWINDOW | SWP_NOZORDER /*| SWP_ASYNCWINDOWPOS*/);
600 } else if (dd->os_hwnd==dd->fs_hwnd) {
601 SetWindowPos(dd->os_hwnd, NULL, 0, 0, dd->store_width+dd->off_w, dd->store_height+dd->off_h, SWP_SHOWWINDOW | SWP_NOZORDER /*| SWP_ASYNCWINDOWPOS*/);
602 }
603 if (!dd->fullscreen || dd->on_secondary_screen) {
604 DD_ShowTaskbar(GF_TRUE);
605 }
606
607
608 #ifndef GPAC_DISABLE_3D
609 if (dd->output_3d) {
610 e = DD_SetupOpenGL(dr, 0, 0);
611 } else
612 #endif
613 {
614 if (!dd->fullscreen && (dd->os_hwnd==dd->fs_hwnd)) {
615 // SetWindowPos(dd->os_hwnd, NULL, 0, 0, dd->store_width+dd->off_w, dd->store_height+dd->off_h, SWP_NOZORDER | SWP_NOMOVE | SWP_ASYNCWINDOWPOS);
616 }
617 /*first time FS, store*/
618 if (!dd->store_width) {
619 dd->store_width = dd->width;
620 dd->store_height = dd->height;
621 }
622 if (dd->fullscreen) {
623 e = InitDirectDraw(dr, dd->fs_width, dd->fs_height);
624 } else {
625 e = InitDirectDraw(dr, dd->store_width, dd->store_height);
626 }
627 }
628
629 if (bOn) {
630 dd->store_width = *outWidth;
631 dd->store_height = *outHeight;
632 *outWidth = dd->fs_width;
633 *outHeight = dd->fs_height;
634 } else {
635 *outWidth = dd->store_width;
636 *outHeight = dd->store_height;
637 }
638 SetForegroundWindow(dd->cur_hwnd);
639 SetFocus(dd->cur_hwnd);
640 return e;
641 }
642
643
DD_Flush(GF_VideoOutput * dr,GF_Window * dest)644 GF_Err DD_Flush(GF_VideoOutput *dr, GF_Window *dest)
645 {
646 RECT rc;
647 HRESULT hr;
648 DDCONTEXT;
649
650 if (!dd) return GF_BAD_PARAM;
651
652 GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[DX] Flushing video output\n"));
653
654 #ifndef GPAC_DISABLE_3D
655
656 if (dd->output_3d) {
657 #if defined(GPAC_USE_GLES1X) || defined(GPAC_USE_GLES2)
658 if (dd->surface) eglSwapBuffers(dd->egldpy, dd->surface);
659 #else
660 SwapBuffers(dd->gl_HDC);
661 #endif
662 return GF_OK;
663 }
664 #endif
665
666
667 if (!dd->ddraw_init) return GF_BAD_PARAM;
668
669 if (!dd->fullscreen && dd->windowless) {
670 HDC hdc;
671 /*lock backbuffer HDC*/
672 dr->LockOSContext(dr, GF_TRUE);
673 /*get window hdc and copy from backbuffer to window*/
674 hdc = GetDC(dd->os_hwnd);
675 BitBlt(hdc, 0, 0, dd->width, dd->height, dd->lock_hdc, 0, 0, SRCCOPY);
676 ReleaseDC(dd->os_hwnd, hdc);
677 /*unlock backbuffer HDC*/
678 dr->LockOSContext(dr, GF_FALSE);
679 return GF_OK;
680 }
681
682 if (!dd->disable_vsync)
683 dd->pDD->lpVtbl->WaitForVerticalBlank(dd->pDD, DDWAITVB_BLOCKBEGIN, NULL);
684
685 if (dest) {
686 POINT pt;
687 pt.x = dest->x;
688 pt.y = dest->y;
689 ClientToScreen(dd->cur_hwnd, &pt);
690 dest->x = pt.x;
691 dest->y = pt.y;
692 MAKERECT(rc, dest);
693 hr = dd->pPrimary->lpVtbl->Blt(dd->pPrimary, &rc, dd->pBack, NULL, DDBLT_WAIT, NULL);
694 } else {
695 hr = dd->pPrimary->lpVtbl->Blt(dd->pPrimary, NULL, dd->pBack, NULL, DDBLT_WAIT, NULL);
696 }
697 if (hr == DDERR_SURFACELOST) {
698 dd->pPrimary->lpVtbl->Restore(dd->pPrimary);
699 dd->pBack->lpVtbl->Restore(dd->pBack);
700 }
701 return FAILED(hr) ? GF_IO_ERR : GF_OK;
702 }
703
704
705
EnumDisplayModes(LPDDSURFDESC lpDDDesc,LPVOID lpContext)706 HRESULT WINAPI EnumDisplayModes( LPDDSURFDESC lpDDDesc, LPVOID lpContext)
707 {
708 DDContext *dd = (DDContext *) lpContext;
709
710 //check W and H
711 if (dd->width <= lpDDDesc->dwWidth && dd->height <= lpDDDesc->dwHeight
712 //check FSW and FSH
713 && dd->fs_width > lpDDDesc->dwWidth && dd->fs_height > lpDDDesc->dwHeight) {
714
715 if (lpDDDesc->dwHeight == 200)
716 return DDENUMRET_OK;
717
718 dd->fs_width = lpDDDesc->dwWidth;
719 dd->fs_height = lpDDDesc->dwHeight;
720
721 return DDENUMRET_CANCEL;
722 }
723 return DDENUMRET_OK;
724 }
725
GetDisplayMode(DDContext * dd)726 GF_Err GetDisplayMode(DDContext *dd)
727 {
728 if (dd->switch_res && dd->DirectDrawCreate) {
729 HRESULT hr;
730 Bool temp_dd = GF_FALSE;
731 if (!dd->pDD) {
732 LPDIRECTDRAW ddraw;
733 dd->DirectDrawCreate(NULL, &ddraw, NULL);
734 ddraw->lpVtbl->QueryInterface(ddraw, &IID_IDirectDraw7, (LPVOID *)&dd->pDD);
735 temp_dd = GF_TRUE;
736 }
737 //we start with a hugde res and downscale
738 dd->fs_width = dd->fs_height = 50000;
739
740 hr = dd->pDD->lpVtbl->EnumDisplayModes(dd->pDD, 0L, NULL, dd, EnumDisplayModes);
741
742 if (temp_dd) SAFE_DD_RELEASE(dd->pDD);
743 if (FAILED(hr)) return GF_IO_ERR;
744 } else {
745 dd->fs_width = GetSystemMetrics(SM_CXSCREEN);
746 dd->fs_height = GetSystemMetrics(SM_CYSCREEN);
747 }
748 return GF_OK;
749 }
750
751
752
NewDXVideoOutput()753 static void *NewDXVideoOutput()
754 {
755 DDContext *pCtx;
756 GF_VideoOutput *driv = (GF_VideoOutput *) gf_malloc(sizeof(GF_VideoOutput));
757 memset(driv, 0, sizeof(GF_VideoOutput));
758 GF_REGISTER_MODULE_INTERFACE(driv, GF_VIDEO_OUTPUT_INTERFACE, "DirectX Video Output", "gpac distribution");
759
760 pCtx = (DDContext*)gf_malloc(sizeof(DDContext));
761 memset(pCtx, 0, sizeof(DDContext));
762 driv->opaque = pCtx;
763 driv->Flush = DD_Flush;
764 driv->Setup = DD_Setup;
765 driv->Shutdown = DD_Shutdown;
766 driv->SetFullScreen = DD_SetFullScreen;
767 driv->ProcessEvent = DD_ProcessEvent;
768
769 #ifdef UNICODE
770 pCtx->hDDrawLib = LoadLibrary(L"ddraw.dll");
771 #else
772 pCtx->hDDrawLib = LoadLibrary("ddraw.dll");
773 #endif
774 if (pCtx->hDDrawLib) {
775 pCtx->DirectDrawCreate = (DIRECTDRAWCREATEPROC) GetProcAddress(pCtx->hDDrawLib, "DirectDrawCreate");
776 }
777
778 driv->max_screen_width = GetSystemMetrics(SM_CXSCREEN);
779 driv->max_screen_height = GetSystemMetrics(SM_CYSCREEN);
780 driv->max_screen_bpp = 8;
781 driv->hw_caps = GF_VIDEO_HW_OPENGL | GF_VIDEO_HW_OPENGL_OFFSCREEN | GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA;
782
783 DD_SetupDDraw(driv);
784
785 return (void *)driv;
786 }
787
DeleteVideoOutput(void * ifce)788 static void DeleteVideoOutput(void *ifce)
789 {
790 GF_VideoOutput *driv = (GF_VideoOutput *) ifce;
791 DDContext *dd = (DDContext *)driv->opaque;
792
793 if (dd->fullscreen) {
794 DD_ShowTaskbar(GF_TRUE);
795 }
796
797 if (dd->hDDrawLib) {
798 FreeLibrary(dd->hDDrawLib);
799 }
800
801 if (dd->caption) gf_free(dd->caption);
802
803 gf_free(dd);
804 gf_free(driv);
805 }
806
807 /*interface query*/
808 GPAC_MODULE_EXPORT
QueryInterfaces()809 const u32 *QueryInterfaces()
810 {
811 static u32 si [] = {
812 GF_VIDEO_OUTPUT_INTERFACE,
813 GF_AUDIO_OUTPUT_INTERFACE,
814 0
815 };
816 return si;
817 }
818 /*interface create*/
819 GPAC_MODULE_EXPORT
LoadInterface(u32 InterfaceType)820 GF_BaseInterface *LoadInterface(u32 InterfaceType)
821 {
822 if (InterfaceType == GF_VIDEO_OUTPUT_INTERFACE) return (GF_BaseInterface*)NewDXVideoOutput();
823 if (InterfaceType == GF_AUDIO_OUTPUT_INTERFACE) return (GF_BaseInterface*)NewAudioOutput();
824 return NULL;
825 }
826 /*interface destroy*/
827 GPAC_MODULE_EXPORT
ShutdownInterface(GF_BaseInterface * ifce)828 void ShutdownInterface(GF_BaseInterface *ifce)
829 {
830 switch (ifce->InterfaceType) {
831 case GF_VIDEO_OUTPUT_INTERFACE:
832 DeleteVideoOutput((GF_VideoOutput *)ifce);
833 break;
834 case GF_AUDIO_OUTPUT_INTERFACE:
835 DeleteDxAudioOutput(ifce);
836 break;
837 }
838 }
839
840 GPAC_MODULE_STATIC_DECLARATION( dx_out )
841