756a6efb48afa8ab8a88b9d5a4b53668d224cce7
[mupen64plus-pandora.git] / source / mupen64plus-core / src / api / vidext.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus-core - api/vidext.c                                       *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
4  *   Copyright (C) 2009 Richard Goedeken                                   *
5  *                                                                         *
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.                                   *
10  *                                                                         *
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.                          *
15  *                                                                         *
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  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21                        
22 /* This file contains the Core video extension functions which will be exported
23  * outside of the core library.
24  */
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <SDL.h>
29
30 #define M64P_CORE_PROTOTYPES 1
31 #include "m64p_types.h"
32 #include "m64p_vidext.h"
33 #include "vidext.h"
34 #include "callbacks.h"
35 #include "../osd/osd.h"
36
37 #if SDL_VERSION_ATLEAST(2,0,0)
38 #include "vidext_sdl2_compat.h"
39 #endif
40
41 #ifdef PANDORA
42 #define USE_EGL_SDL 1
43 #ifdef USE_EGL_SDL
44 #include "eglport.h"
45 #else
46 #include <EGL/egl.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;
53 #endif
54 static int useFB = 0;
55 #endif
56
57 /* local variables */
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;
63
64 /* global function for use by frontend.c */
65 m64p_error OverrideVideoFunctions(m64p_video_extension_functions *VideoFunctionStruct)
66 {
67     /* check input data */
68     if (VideoFunctionStruct == NULL)
69         return M64ERR_INPUT_ASSERT;
70     if (VideoFunctionStruct->Functions < 11)
71         return M64ERR_INPUT_INVALID;
72
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)
85     {
86         l_ExternalVideoFuncTable.Functions = 11;
87         memset(&l_ExternalVideoFuncTable.VidExtFuncInit, 0, 11 * sizeof(void *));
88         l_VideoExtensionActive = 0;
89         return M64ERR_SUCCESS;
90     }
91
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;
96 }
97
98 int VidExt_InFullscreenMode(void)
99 {
100     return l_Fullscreen;
101 }
102
103 int VidExt_VideoRunning(void)
104 {
105     return l_VideoOutputActive;
106 }
107
108 /* video extension functions to be called by the video plugin */
109 EXPORT m64p_error CALL VidExt_Init(void)
110 {
111     /* call video extension override if necessary */
112     if (l_VideoExtensionActive)
113         return (*l_ExternalVideoFuncTable.VidExtFuncInit)();
114
115     if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1)
116     {
117         DebugMessage(M64MSG_ERROR, "SDL video subsystem init failed: %s", SDL_GetError());
118         return M64ERR_SYSTEM_FAIL;
119     }
120
121     return M64ERR_SUCCESS;
122 }
123
124 EXPORT m64p_error CALL VidExt_Quit(void)
125 {
126     /* call video extension override if necessary */
127     if (l_VideoExtensionActive)
128     {
129         m64p_error rval = (*l_ExternalVideoFuncTable.VidExtFuncQuit)();
130         if (rval == M64ERR_SUCCESS)
131         {
132             l_VideoOutputActive = 0;
133             StateChanged(M64CORE_VIDEO_MODE, M64VIDEO_NONE);
134         }
135         return rval;
136     }
137
138     if (!SDL_WasInit(SDL_INIT_VIDEO))
139         return M64ERR_NOT_INIT;
140         #ifdef PANDORA
141         #ifdef USE_EGL_SDL
142         EGL_Close();
143         #else
144         if (eglDisplay) {
145                 eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
146                 if (eglContext)
147                         eglDestroyContext(eglDisplay, eglContext);
148                 if (eglSurface)
149                         eglDestroySurface(eglDisplay, eglSurface);
150                 eglTerminate(eglDisplay);
151         }
152         eglDisplay = NULL;
153         eglContext = NULL;
154         eglSurface = NULL;
155         #endif
156         #endif
157     SDL_ShowCursor(SDL_ENABLE);
158     SDL_QuitSubSystem(SDL_INIT_VIDEO);
159     l_pScreen = NULL;
160     l_VideoOutputActive = 0;
161     StateChanged(M64CORE_VIDEO_MODE, M64VIDEO_NONE);
162
163     return M64ERR_SUCCESS;
164 }
165
166 EXPORT m64p_error CALL VidExt_ListFullscreenModes(m64p_2d_size *SizeArray, int *NumSizes)
167 {
168     const SDL_VideoInfo *videoInfo;
169     unsigned int videoFlags;
170     SDL_Rect **modes;
171     int i;
172
173     /* call video extension override if necessary */
174     if (l_VideoExtensionActive)
175         return (*l_ExternalVideoFuncTable.VidExtFuncListModes)(SizeArray, NumSizes);
176
177     if (!SDL_WasInit(SDL_INIT_VIDEO))
178         return M64ERR_NOT_INIT;
179
180     /* get a list of SDL video modes */
181         #ifdef PANDORA
182     videoFlags = SDL_FULLSCREEN;
183         #else
184     videoFlags = SDL_OPENGL | SDL_FULLSCREEN;
185         #endif
186
187     if ((videoInfo = SDL_GetVideoInfo()) == NULL)
188     {
189         DebugMessage(M64MSG_ERROR, "SDL_GetVideoInfo query failed: %s", SDL_GetError());
190         return M64ERR_SYSTEM_FAIL;
191     }
192         #ifndef PANDORA
193     if(videoInfo->hw_available)
194         videoFlags |= SDL_HWSURFACE;
195     else
196     #endif
197         videoFlags |= SDL_SWSURFACE;
198
199     modes = SDL_ListModes(NULL, videoFlags);
200
201     if (modes == (SDL_Rect **) 0 || modes == (SDL_Rect **) -1)
202     {
203         DebugMessage(M64MSG_WARNING, "No fullscreen SDL video modes available");
204         *NumSizes = 0;
205         return M64ERR_SUCCESS;
206     }
207
208     i = 0;
209     while (i < *NumSizes && modes[i] != NULL)
210     {
211         SizeArray[i].uiWidth  = modes[i]->w;
212         SizeArray[i].uiHeight = modes[i]->h;
213         i++;
214     }
215
216     *NumSizes = i;
217
218     return M64ERR_SUCCESS;
219 }
220
221 EXPORT m64p_error CALL VidExt_SetVideoMode(int Width, int Height, int BitsPerPixel, m64p_video_mode ScreenMode, m64p_video_flags Flags)
222 {
223     const SDL_VideoInfo *videoInfo;
224     int videoFlags = 0;
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)
228     {
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)
233         {
234             StateChanged(M64CORE_VIDEO_MODE, ScreenMode);
235             StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height);
236         }
237         return rval;
238     }
239
240     if (!SDL_WasInit(SDL_INIT_VIDEO)) {
241 printf("SDL was not init, aborting\n");
242         return M64ERR_NOT_INIT;
243     }
244
245     /* Get SDL video flags to use */
246     if (ScreenMode == M64VIDEO_WINDOWED)
247     {
248                 #ifdef PANDORA
249                 videoFlags = 0;
250                 useFB = 0;
251                 #else
252         videoFlags = SDL_OPENGL;
253                 #endif
254         if (Flags & M64VIDEOFLAG_SUPPORT_RESIZING)
255             videoFlags |= SDL_RESIZABLE;
256     }
257     else if (ScreenMode == M64VIDEO_FULLSCREEN)
258     {
259                 #ifdef PANDORA
260         videoFlags = SDL_FULLSCREEN;
261                 #else
262         videoFlags = SDL_OPENGL | SDL_FULLSCREEN;
263                 #endif
264     }
265     else
266     {
267         return M64ERR_INPUT_INVALID;
268     }
269
270     if ((videoInfo = SDL_GetVideoInfo()) == NULL)
271     {
272         DebugMessage(M64MSG_ERROR, "SDL_GetVideoInfo query failed: %s", SDL_GetError());
273         return M64ERR_SYSTEM_FAIL;
274     }
275         #ifndef PANDORA
276     if (videoInfo->hw_available)
277         videoFlags |= SDL_HWSURFACE;
278     else
279     #endif
280         videoFlags |= SDL_SWSURFACE;
281
282     /* set the mode */
283     if (BitsPerPixel > 0)
284         DebugMessage(M64MSG_INFO, "Setting %i-bit video mode: %ix%i", BitsPerPixel, Width, Height);
285     else
286         DebugMessage(M64MSG_INFO, "Setting video mode: %ix%i", Width, Height);
287
288     l_pScreen = SDL_SetVideoMode(Width, Height, BitsPerPixel, videoFlags);
289     if (l_pScreen == NULL)
290     {
291         DebugMessage(M64MSG_ERROR, "SDL_SetVideoMode failed: %s", SDL_GetError());
292         return M64ERR_SYSTEM_FAIL;
293     }
294         #ifdef PANDORA
295         // Setup EGL Context...
296         if ((Width==800) && (Height==480))      // 800x480 => FB and no X11
297                 useFB = 1;              
298 //      Width = 800;
299 //      Height = 480;
300         #ifdef  USE_EGL_SDL
301         EGL_Open(Width, Height);
302         #else
303     EGLint maj, min;
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");
309         }
310         printf("EGL v%i.%i initialized%s\n", maj, min, (useFB)?" using FB":"");
311         EGLint attribs[] =
312         {
313                 EGL_RED_SIZE,        5,
314                 EGL_GREEN_SIZE,      6,
315                 EGL_BLUE_SIZE,       5,
316                 EGL_DEPTH_SIZE,      16,
317                 EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,
318                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
319                 EGL_SAMPLE_BUFFERS,  0,
320                 EGL_SAMPLES,         0,
321                 EGL_NONE
322         };
323         EGLint ctx_attribs[] =
324         {
325                 EGL_CONTEXT_CLIENT_VERSION, 2,
326                 EGL_NONE
327         };
328
329
330         EGLint num_configs;
331         if (!eglChooseConfig(eglDisplay, attribs, &eglConfig, 1, &num_configs) || (num_configs < 1))
332         {
333                 printf("Could not find config for %s (perhaps this API is unsupported?)\n", "GLES2");
334         }
335
336         EGLint vid;
337         if (!eglGetConfigAttrib(eglDisplay, eglConfig, EGL_NATIVE_VISUAL_ID, &vid))
338         {
339                 printf("Could not get native visual ID from chosen config\n");
340         }
341         eglBindAPI(EGL_OPENGL_ES_API);
342
343         eglContext=eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, ctx_attribs);
344         eglSurface=eglCreateWindowSurface(eglDisplay, eglConfig, (NativeWindowType)((useFB)?NULL:sysWmInfo.info.x11.window), NULL);
345
346         if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext))
347         {
348                 printf("eglMakeCurrent() failed\n");
349         }
350         #endif  //eglport
351         #endif
352
353     SDL_ShowCursor(SDL_DISABLE);
354
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;
360 }
361
362 EXPORT m64p_error CALL VidExt_ResizeWindow(int Width, int Height)
363 {
364     const SDL_VideoInfo *videoInfo;
365     int videoFlags = 0;
366
367     /* call video extension override if necessary */
368     if (l_VideoExtensionActive)
369     {
370         m64p_error rval;
371         // shut down the OSD
372         osd_exit();
373         // re-create the OGL context
374         rval = (*l_ExternalVideoFuncTable.VidExtFuncResizeWindow)(Width, Height);
375         if (rval == M64ERR_SUCCESS)
376         {
377             StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height);
378             // re-create the On-Screen Display
379             osd_init(Width, Height);
380         }
381         return rval;
382     }
383
384     if (!l_VideoOutputActive || !SDL_WasInit(SDL_INIT_VIDEO))
385         return M64ERR_NOT_INIT;
386
387     if (l_Fullscreen)
388     {
389         DebugMessage(M64MSG_ERROR, "VidExt_ResizeWindow() called in fullscreen mode.");
390         return M64ERR_INVALID_STATE;
391     }
392
393     /* Get SDL video flags to use */
394         #ifdef PANDORA
395         if (useFB)
396                 return M64ERR_INVALID_STATE;
397     videoFlags = SDL_RESIZABLE;
398         #else
399     videoFlags = SDL_OPENGL | SDL_RESIZABLE;
400         #endif
401     if ((videoInfo = SDL_GetVideoInfo()) == NULL)
402     {
403         DebugMessage(M64MSG_ERROR, "SDL_GetVideoInfo query failed: %s", SDL_GetError());
404         return M64ERR_SYSTEM_FAIL;
405     }
406     #ifndef PANDORA
407     if (videoInfo->hw_available)
408         videoFlags |= SDL_HWSURFACE;
409     else
410     #endif
411         videoFlags |= SDL_SWSURFACE;
412
413     // destroy the On-Screen Display
414     osd_exit();
415
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)
419     {
420         DebugMessage(M64MSG_ERROR, "SDL_SetVideoMode failed: %s", SDL_GetError());
421         return M64ERR_SYSTEM_FAIL;
422     }
423
424     StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height);
425     // re-create the On-Screen Display
426     osd_init(Width, Height);
427     return M64ERR_SUCCESS;
428 }
429
430 EXPORT m64p_error CALL VidExt_SetCaption(const char *Title)
431 {
432     /* call video extension override if necessary */
433     if (l_VideoExtensionActive)
434         return (*l_ExternalVideoFuncTable.VidExtFuncSetCaption)(Title);
435
436     if (!SDL_WasInit(SDL_INIT_VIDEO))
437         return M64ERR_NOT_INIT;
438
439     SDL_WM_SetCaption(Title, "M64+ Video");
440
441     return M64ERR_SUCCESS;
442 }
443
444 EXPORT m64p_error CALL VidExt_ToggleFullScreen(void)
445 {
446     /* call video extension override if necessary */
447     if (l_VideoExtensionActive)
448     {
449         m64p_error rval = (*l_ExternalVideoFuncTable.VidExtFuncToggleFS)();
450         if (rval == M64ERR_SUCCESS)
451         {
452             l_Fullscreen = !l_Fullscreen;
453             StateChanged(M64CORE_VIDEO_MODE, l_Fullscreen ? M64VIDEO_FULLSCREEN : M64VIDEO_WINDOWED);
454         }
455         return rval;
456     }
457
458     if (!SDL_WasInit(SDL_INIT_VIDEO))
459         return M64ERR_NOT_INIT;
460
461     /* TODO:
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);
469 /*      #ifdef PANDORA
470         if (useFB)      // no effect on FB
471                 return M64ERR_INVALID_STATE;
472         #endif*/
473     if (SDL_WM_ToggleFullScreen(l_pScreen) == 1)
474     {
475         l_Fullscreen = !l_Fullscreen;
476         StateChanged(M64CORE_VIDEO_MODE, l_Fullscreen ? M64VIDEO_FULLSCREEN : M64VIDEO_WINDOWED);
477         return M64ERR_SUCCESS;
478     }
479
480     return M64ERR_SYSTEM_FAIL;
481 }
482
483 EXPORT void * CALL VidExt_GL_GetProcAddress(const char* Proc)
484 {
485     /* call video extension override if necessary */
486     if (l_VideoExtensionActive)
487         return (*l_ExternalVideoFuncTable.VidExtFuncGLGetProc)(Proc);
488
489     if (!SDL_WasInit(SDL_INIT_VIDEO))
490         return NULL;
491
492     return SDL_GL_GetProcAddress(Proc);
493 }
494
495 typedef struct {
496     m64p_GLattr m64Attr;
497     SDL_GLattr sdlAttr;
498 } GLAttrMapNode;
499
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 },
510 #else
511         { M64P_GL_SWAP_CONTROL, SDL_GL_SWAP_CONTROL },
512 #endif
513         { M64P_GL_MULTISAMPLEBUFFERS, SDL_GL_MULTISAMPLEBUFFERS },
514         { M64P_GL_MULTISAMPLESAMPLES, SDL_GL_MULTISAMPLESAMPLES }};
515 static const int mapSize = sizeof(GLAttrMap) / sizeof(GLAttrMapNode);
516
517 EXPORT m64p_error CALL VidExt_GL_SetAttribute(m64p_GLattr Attr, int Value)
518 {
519     int i;
520
521     /* call video extension override if necessary */
522     if (l_VideoExtensionActive)
523         return (*l_ExternalVideoFuncTable.VidExtFuncGLSetAttr)(Attr, Value);
524
525     if (!SDL_WasInit(SDL_INIT_VIDEO))
526         return M64ERR_NOT_INIT;
527
528         #ifdef PANDORA
529         return M64ERR_SUCCESS;
530         #else
531     for (i = 0; i < mapSize; i++)
532     {
533         if (GLAttrMap[i].m64Attr == Attr)
534         {
535             if (SDL_GL_SetAttribute(GLAttrMap[i].sdlAttr, Value) != 0)
536                 return M64ERR_SYSTEM_FAIL;
537             return M64ERR_SUCCESS;
538         }
539     }
540
541     return M64ERR_INPUT_INVALID;
542     #endif
543 }
544
545 EXPORT m64p_error CALL VidExt_GL_GetAttribute(m64p_GLattr Attr, int *pValue)
546 {
547     int i;
548
549     /* call video extension override if necessary */
550     if (l_VideoExtensionActive)
551         return (*l_ExternalVideoFuncTable.VidExtFuncGLGetAttr)(Attr, pValue);
552
553     if (!SDL_WasInit(SDL_INIT_VIDEO))
554         return M64ERR_NOT_INIT;
555
556         #ifdef PANDORA
557         return M64ERR_SUCCESS;
558         #else
559     for (i = 0; i < mapSize; i++)
560     {
561         if (GLAttrMap[i].m64Attr == Attr)
562         {
563             int NewValue = 0;
564             if (SDL_GL_GetAttribute(GLAttrMap[i].sdlAttr, &NewValue) != 0)
565                 return M64ERR_SYSTEM_FAIL;
566             *pValue = NewValue;
567             return M64ERR_SUCCESS;
568         }
569     }
570
571     return M64ERR_INPUT_INVALID;
572     #endif
573 }
574
575 EXPORT m64p_error CALL VidExt_GL_SwapBuffers(void)
576 {
577     /* call video extension override if necessary */
578     if (l_VideoExtensionActive)
579         return (*l_ExternalVideoFuncTable.VidExtFuncGLSwapBuf)();
580
581     if (!SDL_WasInit(SDL_INIT_VIDEO))
582         return M64ERR_NOT_INIT;
583         #ifdef PANDORA
584         #ifdef USE_EGL_SDL
585         EGL_SwapBuffers();
586         #else
587         eglSwapBuffers( eglDisplay, eglSurface );
588         #endif
589         #else
590     SDL_GL_SwapBuffers();
591         #endif
592     return M64ERR_SUCCESS;
593 }
594
595