1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus-core - api/vidext.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2009 Richard Goedeken *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
20 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22 /* This file contains the Core video extension functions which will be exported
23 * outside of the core library.
30 #define M64P_CORE_PROTOTYPES 1
31 #include "m64p_types.h"
32 #include "m64p_vidext.h"
34 #include "callbacks.h"
35 #include "../osd/osd.h"
37 #if SDL_VERSION_ATLEAST(2,0,0)
38 #include "vidext_sdl2_compat.h"
47 #include <SDL_syswm.h>
48 SDL_SysWMinfo sysWmInfo;
49 static EGLSurface eglSurface = NULL;
50 static EGLContext eglContext = NULL;
51 static EGLConfig eglConfig = NULL;
52 static EGLDisplay eglDisplay = NULL;
58 static m64p_video_extension_functions l_ExternalVideoFuncTable = {10, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
59 static int l_VideoExtensionActive = 0;
60 static int l_VideoOutputActive = 0;
61 static int l_Fullscreen = 0;
62 static SDL_Surface *l_pScreen = NULL;
64 /* global function for use by frontend.c */
65 m64p_error OverrideVideoFunctions(m64p_video_extension_functions *VideoFunctionStruct)
67 /* check input data */
68 if (VideoFunctionStruct == NULL)
69 return M64ERR_INPUT_ASSERT;
70 if (VideoFunctionStruct->Functions < 11)
71 return M64ERR_INPUT_INVALID;
73 /* disable video extension if any of the function pointers are NULL */
74 if (VideoFunctionStruct->VidExtFuncInit == NULL ||
75 VideoFunctionStruct->VidExtFuncQuit == NULL ||
76 VideoFunctionStruct->VidExtFuncListModes == NULL ||
77 VideoFunctionStruct->VidExtFuncSetMode == NULL ||
78 VideoFunctionStruct->VidExtFuncGLGetProc == NULL ||
79 VideoFunctionStruct->VidExtFuncGLSetAttr == NULL ||
80 VideoFunctionStruct->VidExtFuncGLGetAttr == NULL ||
81 VideoFunctionStruct->VidExtFuncGLSwapBuf == NULL ||
82 VideoFunctionStruct->VidExtFuncSetCaption == NULL ||
83 VideoFunctionStruct->VidExtFuncToggleFS == NULL ||
84 VideoFunctionStruct->VidExtFuncResizeWindow == NULL)
86 l_ExternalVideoFuncTable.Functions = 11;
87 memset(&l_ExternalVideoFuncTable.VidExtFuncInit, 0, 11 * sizeof(void *));
88 l_VideoExtensionActive = 0;
89 return M64ERR_SUCCESS;
92 /* otherwise copy in the override function pointers */
93 memcpy(&l_ExternalVideoFuncTable, VideoFunctionStruct, sizeof(m64p_video_extension_functions));
94 l_VideoExtensionActive = 1;
95 return M64ERR_SUCCESS;
98 int VidExt_InFullscreenMode(void)
103 int VidExt_VideoRunning(void)
105 return l_VideoOutputActive;
108 /* video extension functions to be called by the video plugin */
109 EXPORT m64p_error CALL VidExt_Init(void)
111 /* call video extension override if necessary */
112 if (l_VideoExtensionActive)
113 return (*l_ExternalVideoFuncTable.VidExtFuncInit)();
115 if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1)
117 DebugMessage(M64MSG_ERROR, "SDL video subsystem init failed: %s", SDL_GetError());
118 return M64ERR_SYSTEM_FAIL;
121 return M64ERR_SUCCESS;
124 EXPORT m64p_error CALL VidExt_Quit(void)
126 /* call video extension override if necessary */
127 if (l_VideoExtensionActive)
129 m64p_error rval = (*l_ExternalVideoFuncTable.VidExtFuncQuit)();
130 if (rval == M64ERR_SUCCESS)
132 l_VideoOutputActive = 0;
133 StateChanged(M64CORE_VIDEO_MODE, M64VIDEO_NONE);
138 if (!SDL_WasInit(SDL_INIT_VIDEO))
139 return M64ERR_NOT_INIT;
145 eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
147 eglDestroyContext(eglDisplay, eglContext);
149 eglDestroySurface(eglDisplay, eglSurface);
150 eglTerminate(eglDisplay);
157 SDL_ShowCursor(SDL_ENABLE);
158 SDL_QuitSubSystem(SDL_INIT_VIDEO);
160 l_VideoOutputActive = 0;
161 StateChanged(M64CORE_VIDEO_MODE, M64VIDEO_NONE);
163 return M64ERR_SUCCESS;
166 EXPORT m64p_error CALL VidExt_ListFullscreenModes(m64p_2d_size *SizeArray, int *NumSizes)
168 const SDL_VideoInfo *videoInfo;
169 unsigned int videoFlags;
173 /* call video extension override if necessary */
174 if (l_VideoExtensionActive)
175 return (*l_ExternalVideoFuncTable.VidExtFuncListModes)(SizeArray, NumSizes);
177 if (!SDL_WasInit(SDL_INIT_VIDEO))
178 return M64ERR_NOT_INIT;
180 /* get a list of SDL video modes */
182 videoFlags = SDL_FULLSCREEN;
184 videoFlags = SDL_OPENGL | SDL_FULLSCREEN;
187 if ((videoInfo = SDL_GetVideoInfo()) == NULL)
189 DebugMessage(M64MSG_ERROR, "SDL_GetVideoInfo query failed: %s", SDL_GetError());
190 return M64ERR_SYSTEM_FAIL;
193 if(videoInfo->hw_available)
194 videoFlags |= SDL_HWSURFACE;
197 videoFlags |= SDL_SWSURFACE;
199 modes = SDL_ListModes(NULL, videoFlags);
201 if (modes == (SDL_Rect **) 0 || modes == (SDL_Rect **) -1)
203 DebugMessage(M64MSG_WARNING, "No fullscreen SDL video modes available");
205 return M64ERR_SUCCESS;
209 while (i < *NumSizes && modes[i] != NULL)
211 SizeArray[i].uiWidth = modes[i]->w;
212 SizeArray[i].uiHeight = modes[i]->h;
218 return M64ERR_SUCCESS;
221 EXPORT m64p_error CALL VidExt_SetVideoMode(int Width, int Height, int BitsPerPixel, m64p_video_mode ScreenMode, m64p_video_flags Flags)
223 const SDL_VideoInfo *videoInfo;
225 printf("VidExt_SetVideoMode(%i, %i, %i, %s, %x)\n", Width, Height, BitsPerPixel, (ScreenMode==M64VIDEO_WINDOWED)?"Windowed":"Fullscreen", Flags);
226 /* call video extension override if necessary */
227 if (l_VideoExtensionActive)
229 m64p_error rval = (*l_ExternalVideoFuncTable.VidExtFuncSetMode)(Width, Height, BitsPerPixel, ScreenMode, Flags);
230 l_Fullscreen = (rval == M64ERR_SUCCESS && ScreenMode == M64VIDEO_FULLSCREEN);
231 l_VideoOutputActive = (rval == M64ERR_SUCCESS);
232 if (l_VideoOutputActive)
234 StateChanged(M64CORE_VIDEO_MODE, ScreenMode);
235 StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height);
240 if (!SDL_WasInit(SDL_INIT_VIDEO)) {
241 printf("SDL was not init, aborting\n");
242 return M64ERR_NOT_INIT;
245 /* Get SDL video flags to use */
246 if (ScreenMode == M64VIDEO_WINDOWED)
252 videoFlags = SDL_OPENGL;
254 if (Flags & M64VIDEOFLAG_SUPPORT_RESIZING)
255 videoFlags |= SDL_RESIZABLE;
257 else if (ScreenMode == M64VIDEO_FULLSCREEN)
260 videoFlags = SDL_FULLSCREEN;
262 videoFlags = SDL_OPENGL | SDL_FULLSCREEN;
267 return M64ERR_INPUT_INVALID;
270 if ((videoInfo = SDL_GetVideoInfo()) == NULL)
272 DebugMessage(M64MSG_ERROR, "SDL_GetVideoInfo query failed: %s", SDL_GetError());
273 return M64ERR_SYSTEM_FAIL;
276 if (videoInfo->hw_available)
277 videoFlags |= SDL_HWSURFACE;
280 videoFlags |= SDL_SWSURFACE;
283 if (BitsPerPixel > 0)
284 DebugMessage(M64MSG_INFO, "Setting %i-bit video mode: %ix%i", BitsPerPixel, Width, Height);
286 DebugMessage(M64MSG_INFO, "Setting video mode: %ix%i", Width, Height);
288 l_pScreen = SDL_SetVideoMode(Width, Height, BitsPerPixel, videoFlags);
289 if (l_pScreen == NULL)
291 DebugMessage(M64MSG_ERROR, "SDL_SetVideoMode failed: %s", SDL_GetError());
292 return M64ERR_SYSTEM_FAIL;
295 // Setup EGL Context...
296 // if ((Width==800) && (Height==480)) // 800x480 => FB and no X11
301 EGL_Open(Width, Height);
304 SDL_VERSION(&sysWmInfo.version);
305 SDL_GetWMInfo(&sysWmInfo);
306 eglDisplay = eglGetDisplay( (useFB)? EGL_DEFAULT_DISPLAY:(EGLNativeDisplayType)sysWmInfo.info.x11.display );
307 if (!eglInitialize(eglDisplay, &maj, &min)) {
308 printf("eglinfo: eglInitialize failed\n");
310 printf("EGL v%i.%i initialized%s\n", maj, min, (useFB)?" using FB":"");
317 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
318 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
319 EGL_SAMPLE_BUFFERS, 0,
323 EGLint ctx_attribs[] =
325 EGL_CONTEXT_CLIENT_VERSION, 2,
331 if (!eglChooseConfig(eglDisplay, attribs, &eglConfig, 1, &num_configs) || (num_configs < 1))
333 printf("Could not find config for %s (perhaps this API is unsupported?)\n", "GLES2");
337 if (!eglGetConfigAttrib(eglDisplay, eglConfig, EGL_NATIVE_VISUAL_ID, &vid))
339 printf("Could not get native visual ID from chosen config\n");
341 eglBindAPI(EGL_OPENGL_ES_API);
343 eglContext=eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, ctx_attribs);
344 eglSurface=eglCreateWindowSurface(eglDisplay, eglConfig, (NativeWindowType)((useFB)?NULL:sysWmInfo.info.x11.window), NULL);
346 if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext))
348 printf("eglMakeCurrent() failed\n");
353 SDL_ShowCursor(SDL_DISABLE);
355 l_Fullscreen = (ScreenMode == M64VIDEO_FULLSCREEN);
356 l_VideoOutputActive = 1;
357 StateChanged(M64CORE_VIDEO_MODE, ScreenMode);
358 StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height);
359 return M64ERR_SUCCESS;
362 EXPORT m64p_error CALL VidExt_ResizeWindow(int Width, int Height)
364 const SDL_VideoInfo *videoInfo;
367 /* call video extension override if necessary */
368 if (l_VideoExtensionActive)
373 // re-create the OGL context
374 rval = (*l_ExternalVideoFuncTable.VidExtFuncResizeWindow)(Width, Height);
375 if (rval == M64ERR_SUCCESS)
377 StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height);
378 // re-create the On-Screen Display
379 osd_init(Width, Height);
384 if (!l_VideoOutputActive || !SDL_WasInit(SDL_INIT_VIDEO))
385 return M64ERR_NOT_INIT;
389 DebugMessage(M64MSG_ERROR, "VidExt_ResizeWindow() called in fullscreen mode.");
390 return M64ERR_INVALID_STATE;
393 /* Get SDL video flags to use */
396 return M64ERR_INVALID_STATE;
397 videoFlags = SDL_RESIZABLE;
399 videoFlags = SDL_OPENGL | SDL_RESIZABLE;
401 if ((videoInfo = SDL_GetVideoInfo()) == NULL)
403 DebugMessage(M64MSG_ERROR, "SDL_GetVideoInfo query failed: %s", SDL_GetError());
404 return M64ERR_SYSTEM_FAIL;
407 if (videoInfo->hw_available)
408 videoFlags |= SDL_HWSURFACE;
411 videoFlags |= SDL_SWSURFACE;
413 // destroy the On-Screen Display
416 /* set the re-sizing the screen will create a new OpenGL context */
417 l_pScreen = SDL_SetVideoMode(Width, Height, 0, videoFlags);
418 if (l_pScreen == NULL)
420 DebugMessage(M64MSG_ERROR, "SDL_SetVideoMode failed: %s", SDL_GetError());
421 return M64ERR_SYSTEM_FAIL;
424 StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height);
425 // re-create the On-Screen Display
426 osd_init(Width, Height);
427 return M64ERR_SUCCESS;
430 EXPORT m64p_error CALL VidExt_SetCaption(const char *Title)
432 /* call video extension override if necessary */
433 if (l_VideoExtensionActive)
434 return (*l_ExternalVideoFuncTable.VidExtFuncSetCaption)(Title);
436 if (!SDL_WasInit(SDL_INIT_VIDEO))
437 return M64ERR_NOT_INIT;
439 SDL_WM_SetCaption(Title, "M64+ Video");
441 return M64ERR_SUCCESS;
444 EXPORT m64p_error CALL VidExt_ToggleFullScreen(void)
446 /* call video extension override if necessary */
447 if (l_VideoExtensionActive)
449 m64p_error rval = (*l_ExternalVideoFuncTable.VidExtFuncToggleFS)();
450 if (rval == M64ERR_SUCCESS)
452 l_Fullscreen = !l_Fullscreen;
453 StateChanged(M64CORE_VIDEO_MODE, l_Fullscreen ? M64VIDEO_FULLSCREEN : M64VIDEO_WINDOWED);
458 if (!SDL_WasInit(SDL_INIT_VIDEO))
459 return M64ERR_NOT_INIT;
462 * SDL_WM_ToggleFullScreen doesn't work under Windows and others
463 * (see http://wiki.libsdl.org/moin.cgi/FAQWindows for explanation).
464 * Instead, we should call SDL_SetVideoMode with the SDL_FULLSCREEN flag.
465 * (see http://sdl.beuc.net/sdl.wiki/SDL_SetVideoMode), but on Windows
466 * this resets the OpenGL context and video plugins don't support it yet.
467 * Uncomment the next line to test it: */
468 //return VidExt_SetVideoMode(l_pScreen->w, l_pScreen->h, l_pScreen->format->BitsPerPixel, l_Fullscreen ? M64VIDEO_WINDOWED : M64VIDEO_FULLSCREEN);
470 if (useFB) // no effect on FB
471 return M64ERR_INVALID_STATE;
473 if (SDL_WM_ToggleFullScreen(l_pScreen) == 1)
475 l_Fullscreen = !l_Fullscreen;
476 StateChanged(M64CORE_VIDEO_MODE, l_Fullscreen ? M64VIDEO_FULLSCREEN : M64VIDEO_WINDOWED);
477 return M64ERR_SUCCESS;
480 return M64ERR_SYSTEM_FAIL;
483 EXPORT void * CALL VidExt_GL_GetProcAddress(const char* Proc)
485 /* call video extension override if necessary */
486 if (l_VideoExtensionActive)
487 return (*l_ExternalVideoFuncTable.VidExtFuncGLGetProc)(Proc);
489 if (!SDL_WasInit(SDL_INIT_VIDEO))
492 return SDL_GL_GetProcAddress(Proc);
500 static const GLAttrMapNode GLAttrMap[] = {
501 { M64P_GL_DOUBLEBUFFER, SDL_GL_DOUBLEBUFFER },
502 { M64P_GL_BUFFER_SIZE, SDL_GL_BUFFER_SIZE },
503 { M64P_GL_DEPTH_SIZE, SDL_GL_DEPTH_SIZE },
504 { M64P_GL_RED_SIZE, SDL_GL_RED_SIZE },
505 { M64P_GL_GREEN_SIZE, SDL_GL_GREEN_SIZE },
506 { M64P_GL_BLUE_SIZE, SDL_GL_BLUE_SIZE },
507 { M64P_GL_ALPHA_SIZE, SDL_GL_ALPHA_SIZE },
508 #if SDL_VERSION_ATLEAST(1,3,0)
509 { M64P_GL_SWAP_CONTROL, SDL_RENDERER_PRESENTVSYNC },
511 { M64P_GL_SWAP_CONTROL, SDL_GL_SWAP_CONTROL },
513 { M64P_GL_MULTISAMPLEBUFFERS, SDL_GL_MULTISAMPLEBUFFERS },
514 { M64P_GL_MULTISAMPLESAMPLES, SDL_GL_MULTISAMPLESAMPLES }};
515 static const int mapSize = sizeof(GLAttrMap) / sizeof(GLAttrMapNode);
517 EXPORT m64p_error CALL VidExt_GL_SetAttribute(m64p_GLattr Attr, int Value)
521 /* call video extension override if necessary */
522 if (l_VideoExtensionActive)
523 return (*l_ExternalVideoFuncTable.VidExtFuncGLSetAttr)(Attr, Value);
525 if (!SDL_WasInit(SDL_INIT_VIDEO))
526 return M64ERR_NOT_INIT;
529 return M64ERR_SUCCESS;
531 for (i = 0; i < mapSize; i++)
533 if (GLAttrMap[i].m64Attr == Attr)
535 if (SDL_GL_SetAttribute(GLAttrMap[i].sdlAttr, Value) != 0)
536 return M64ERR_SYSTEM_FAIL;
537 return M64ERR_SUCCESS;
541 return M64ERR_INPUT_INVALID;
545 EXPORT m64p_error CALL VidExt_GL_GetAttribute(m64p_GLattr Attr, int *pValue)
549 /* call video extension override if necessary */
550 if (l_VideoExtensionActive)
551 return (*l_ExternalVideoFuncTable.VidExtFuncGLGetAttr)(Attr, pValue);
553 if (!SDL_WasInit(SDL_INIT_VIDEO))
554 return M64ERR_NOT_INIT;
557 return M64ERR_SUCCESS;
559 for (i = 0; i < mapSize; i++)
561 if (GLAttrMap[i].m64Attr == Attr)
564 if (SDL_GL_GetAttribute(GLAttrMap[i].sdlAttr, &NewValue) != 0)
565 return M64ERR_SYSTEM_FAIL;
567 return M64ERR_SUCCESS;
571 return M64ERR_INPUT_INVALID;
575 EXPORT m64p_error CALL VidExt_GL_SwapBuffers(void)
577 /* call video extension override if necessary */
578 if (l_VideoExtensionActive)
579 return (*l_ExternalVideoFuncTable.VidExtFuncGLSwapBuf)();
581 if (!SDL_WasInit(SDL_INIT_VIDEO))
582 return M64ERR_NOT_INIT;
587 eglSwapBuffers( eglDisplay, eglSurface );
590 SDL_GL_SwapBuffers();
592 return M64ERR_SUCCESS;