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