drm/gl context stuff
[mupen64plus-pandora.git] / source / mupen64plus-core / src / api / eglport.cpp
1 /**
2  *
3  *  EGLPORT.C
4  *  Copyright (C) 2011-2013 Scott R. Smith
5  *
6  *  Permission is hereby granted, free of charge, to any person obtaining a copy
7  *  of this software and associated documentation files (the "Software"), to deal
8  *  in the Software without restriction, including without limitation the rights
9  *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  *  copies of the Software, and to permit persons to whom the Software is
11  *  furnished to do so, subject to the following conditions:
12  *
13  *  The above copyright notice and this permission notice shall be included in
14  *  all copies or substantial portions of the Software.
15  *
16  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  *  THE SOFTWARE.
23  *
24  */
25
26 #include "eglport.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #define USE_EGL_SDL 1
32 #define USE_GLES2       1
33
34 #if defined(USE_EGL_SDL)
35 #include "SDL.h"
36 #include "SDL_syswm.h"
37 SDL_SysWMinfo sysWmInfo;      /** Holds our X Display/Window information */
38 #endif /* USE_EGL_SDL */
39
40 #if defined(PANDORA) /* Pandora VSync Support */
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <sys/ioctl.h>
44 #include <linux/fb.h>
45
46 #ifndef FBIO_WAITFORVSYNC
47 #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
48 #endif
49 int fbdev = -1;
50
51 #elif defined(RPI)
52 #include "bcm_host.h"
53 #endif /* PANDORA */
54
55 enum EGL_RENDER_T {
56     RENDER_RAW=0,           /** Sets render mode to raw or framebuffer mode. */
57     RENDER_SDL,             /** Sets render mode to X11/SDL mode. */
58     RENDER_TOTAL
59 };
60
61 enum EGL_SETTINGS_T {
62     CFG_MODE=0,             /** Render mode for EGL 0=RAW 1=SDL. */
63     CFG_VSYNC,              /** Controls system vsync if available. */
64     CFG_FSAA,               /** Number of samples for full screen AA. 0 is off, 2/4 samples. */
65     CFG_FPS,                /** Calculate and report frame per second. */
66     CFG_RED_SIZE,           /** Number of bits of Red in the color buffer. */
67     CFG_GREEN_SIZE,         /** Number of bits of Green in the color buffer. */
68     CFG_BLUE_SIZE,          /** Number of bits of Blue in the color buffer. */
69     CFG_ALPHA_SIZE,         /** Number of bits of Alpha in the color buffer. */
70     CFG_DEPTH_SIZE,         /** Number of bits of Z in the depth buffer. */
71     CFG_BUFFER_SIZE,        /** The total color component bits in the color buffer. */
72     CFG_STENCIL_SIZE,       /** Number of bits of Stencil in the stencil buffer. */
73     CFG_TOTAL               /** Total number of settings. */
74 };
75
76 NativeDisplayType   nativeDisplay = 0;      /** Reference to the systems native display */
77 NativeWindowType    nativeWindow  = 0;      /** Reference to the systems native window */
78 EGLint              eglSettings[CFG_TOTAL]; /** Stores setting values. */
79 EGLDisplay          eglDisplay    = NULL;   /** Reference to the EGL display */
80 EGLConfig           eglConfig     = NULL;   /** Reference to the EGL config */
81 EGLContext          eglContext    = NULL;   /** Reference to the EGL context */
82 EGLSurface          eglSurface    = NULL;   /** Reference to the EGL surface */
83
84 #define     totalConfigsIn 5                /** Total number of configurations to request */
85 EGLint      totalConfigsFound = 0;          /** Total number of configurations matching attributes */
86 EGLConfig   eglConfigs[totalConfigsIn];     /** Structure containing references to matching configurations */
87
88 uint32_t    fpsCount    = 0;                /** Total number of frames counted */
89 uint32_t    fpsTime     = 0;                /** Start time of frame count measurment */
90
91 int8_t  eglColorbits    = 0;
92 int8_t  eglDepthbits    = 0;
93 int8_t  eglStencilbits  = 0;
94
95
96 /** Private API */
97 void        OpenCfg                 ( const char* file );
98 int8_t      ConfigureEGL            ( EGLConfig config );
99 int8_t      FindEGLConfigs          ( void );
100 int8_t      CheckEGLErrors          ( const char* file, uint16_t line );
101
102 int8_t      GetNativeDisplay        ( void );
103 int8_t      GetNativeWindow         ( uint16_t width, uint16_t height );
104 void        FreeNativeDisplay       ( void );
105 void        FreeNativeWindow        ( void );
106
107 void        Platform_Open           ( void );
108 void        Platform_Close          ( void );
109 void        Platform_VSync          ( void );
110 uint32_t    Platform_GetTicks       ( void );
111
112 static void drm_do_swap(void);
113
114 /** @brief Release all EGL and system resources
115  */
116 void EGL_Close( void )
117 {
118     /* Release EGL resources */
119     if (eglDisplay != NULL)
120     {
121         peglMakeCurrent( eglDisplay, NULL, NULL, EGL_NO_CONTEXT );
122         if (eglContext != NULL) {
123             peglDestroyContext( eglDisplay, eglContext );
124         }
125         if (eglSurface != NULL) {
126             peglDestroySurface( eglDisplay, eglSurface );
127         }
128         peglTerminate( eglDisplay );
129     }
130
131     eglSurface = NULL;
132     eglContext = NULL;
133     eglDisplay = NULL;
134         
135         eglColorbits = 0;
136         eglDepthbits = 0;
137         eglStencilbits = 0;
138
139     /* Release platform resources */
140     FreeNativeWindow();
141     FreeNativeDisplay();
142     Platform_Close();
143
144     CheckEGLErrors( __FILE__, __LINE__ );
145
146     printf( "EGLport: Closed\n" );
147 }
148
149 /** @brief Swap the surface buffer onto the display
150  */
151 void EGL_SwapBuffers( void )
152 {
153     if (eglSettings[CFG_VSYNC] != 0) {
154         Platform_VSync();
155     }
156
157     peglSwapBuffers( eglDisplay, eglSurface );
158     drm_do_swap();
159
160     if (eglSettings[CFG_FPS] != 0) {
161         fpsCount++;
162
163         if (fpsTime - Platform_GetTicks() >= 1000)
164         {
165             printf( "EGLport: %d fps\n", fpsCount );
166             fpsTime = Platform_GetTicks();
167             fpsCount = 0;
168         }
169     }
170 }
171
172 /** @brief Obtain the system display and initialize EGL
173  * @param width : desired pixel width of the window (not used by all platforms)
174  * @param height : desired pixel height of the window (not used by all platforms)
175  * @return : 0 if the function passed, else 1
176  */
177 int8_t EGL_Open( uint16_t width, uint16_t height )
178 {
179     EGLint eglMajorVer, eglMinorVer;
180     EGLBoolean result;
181     uint32_t configIndex = 0;
182     const char* output;
183
184     static const EGLint contextAttribs[] =
185     {
186 #if defined(USE_GLES2)
187           EGL_CONTEXT_CLIENT_VERSION,     2,
188 #endif
189           EGL_NONE
190     };
191
192 #if defined(DEBUG)
193     printf( "EGLport Warning: DEBUG is enabled which may effect performance\n" );
194 #endif
195
196     /* Check that system is not open */
197     if (eglDisplay != NULL || eglContext != NULL || eglSurface != NULL)
198     {
199         printf( "EGLport ERROR: EGL system is already open!\n" );
200         return 1;
201     }
202
203     /* Check for the cfg file to alternative settings */
204     OpenCfg( "eglport.cfg" );
205
206     /* Setup any platform specific bits */
207     Platform_Open();
208
209     printf( "EGLport: Opening EGL display\n" );
210     if (GetNativeDisplay() != 0)
211     {
212         printf( "EGLport ERROR: Unable to obtain native display!\n" );
213         return 1;
214     }
215
216     eglDisplay = peglGetDisplay( nativeDisplay );
217     if (eglDisplay == EGL_NO_DISPLAY)
218     {
219         CheckEGLErrors( __FILE__, __LINE__ );
220         printf( "EGLport ERROR: Unable to create EGL display.\n" );
221         return 1;
222     }
223
224     printf( "EGLport: Initializing\n" );
225     result = peglInitialize( eglDisplay, &eglMajorVer, &eglMinorVer );
226     if (result != EGL_TRUE )
227     {
228         CheckEGLErrors( __FILE__, __LINE__ );
229         printf( "EGLport ERROR: Unable to initialize EGL display.\n" );
230         return 1;
231     }
232
233     /* Get EGL Library Information */
234     printf( "EGL Implementation Version: Major %d Minor %d\n", eglMajorVer, eglMinorVer );
235     output = peglQueryString( eglDisplay, EGL_VENDOR );
236     printf( "EGL_VENDOR: %s\n", output );
237     output = peglQueryString( eglDisplay, EGL_VERSION );
238     printf( "EGL_VERSION: %s\n", output );
239     output = peglQueryString( eglDisplay, EGL_EXTENSIONS );
240     printf( "EGL_EXTENSIONS: %s\n", output );
241
242     if (FindEGLConfigs() != 0)
243     {
244         printf( "EGLport ERROR: Unable to configure EGL. See previous error.\n" );
245         return 1;
246     }
247
248     printf( "EGLport: Using Config %d\n", configIndex );
249 #if defined(EGL_VERSION_1_2)
250     /* Bind GLES and create the context */
251     printf( "EGLport: Binding API\n" );
252     result = peglBindAPI( EGL_OPENGL_ES_API );
253     if ( result == EGL_FALSE )
254     {
255         CheckEGLErrors( __FILE__, __LINE__ );
256         printf( "EGLport ERROR: Could not bind EGL API.\n" );
257         return 1;
258     }
259 #endif /* EGL_VERSION_1_2 */
260
261     printf( "EGLport: Creating Context\n" );
262     eglContext = peglCreateContext( eglDisplay, eglConfigs[configIndex], NULL, contextAttribs );
263     if (eglContext == EGL_NO_CONTEXT)
264     {
265         CheckEGLErrors( __FILE__, __LINE__ );
266         printf( "EGLport ERROR: Unable to create GLES context!\n");
267         return 1;
268     }
269
270     printf( "EGLport: Creating window surface\n" );
271     if (GetNativeWindow( width, height ) != 0)
272     {
273         printf( "EGLport ERROR: Unable to obtain native window!\n" );
274         return 1;
275     }
276
277     eglSurface = peglCreateWindowSurface( eglDisplay, eglConfigs[configIndex], nativeWindow, 0 );
278     if (eglSurface == EGL_NO_SURFACE)
279     {
280         CheckEGLErrors( __FILE__, __LINE__ );
281         printf( "EGLport ERROR: Unable to create EGL surface!\n" );
282         return 1;
283     }
284
285     printf( "EGLport: Making Current\n" );
286     result = peglMakeCurrent( eglDisplay,  eglSurface,  eglSurface, eglContext );
287     if (result != EGL_TRUE)
288     {
289         CheckEGLErrors( __FILE__, __LINE__ );
290         printf( "EGLport ERROR: Unable to make GLES context current\n" );
291         return 1;
292     }
293
294         {
295           EGLint color, depth, stencil;
296           eglGetConfigAttrib(eglDisplay, eglConfigs[configIndex], EGL_BUFFER_SIZE, &color);
297           eglGetConfigAttrib(eglDisplay, eglConfigs[configIndex], EGL_DEPTH_SIZE, &depth);
298           eglGetConfigAttrib(eglDisplay, eglConfigs[configIndex], EGL_STENCIL_SIZE, &stencil);
299           eglColorbits = (color==16)?5:8; //quick hack
300           eglDepthbits = depth;
301           eglStencilbits = stencil;
302         }
303
304     printf( "EGLport: Setting swap interval\n" );
305     peglSwapInterval( eglDisplay, (eglSettings[CFG_VSYNC] > 0) ? 1 : 0 );
306
307     printf( "EGLport: Complete\n" );
308
309     CheckEGLErrors( __FILE__, __LINE__ );
310         
311     return 0;
312 }
313
314 /** @brief Read settings that configure how to use EGL
315  * @param file : name of the config file
316  */
317 void OpenCfg ( const char* file )
318 {
319     #define MAX_STRING 20
320     #define MAX_SIZE 100
321     uint8_t i;
322     FILE* fp = NULL;
323     char* location = NULL;
324     char eglStrings[CFG_TOTAL][MAX_STRING];
325     char buffer[MAX_SIZE];
326
327     strncpy( eglStrings[CFG_MODE], "egl_mode=", MAX_STRING );
328     strncpy( eglStrings[CFG_VSYNC], "use_vsync=", MAX_STRING );
329     strncpy( eglStrings[CFG_FSAA], "use_fsaa=", MAX_STRING );
330     strncpy( eglStrings[CFG_RED_SIZE], "size_red=", MAX_STRING );
331     strncpy( eglStrings[CFG_GREEN_SIZE], "size_green=", MAX_STRING );
332     strncpy( eglStrings[CFG_BLUE_SIZE], "size_blue=", MAX_STRING );
333     strncpy( eglStrings[CFG_ALPHA_SIZE], "size_alpha=", MAX_STRING );
334     strncpy( eglStrings[CFG_DEPTH_SIZE], "size_depth=", MAX_STRING );
335     strncpy( eglStrings[CFG_BUFFER_SIZE], "size_buffer=", MAX_STRING );
336     strncpy( eglStrings[CFG_STENCIL_SIZE], "size_stencil=", MAX_STRING );
337
338     /* Set defaults */
339 //#if defined(USE_EGL_SDL)
340 //    eglSettings[CFG_MODE]           = RENDER_SDL;
341 //#else
342     eglSettings[CFG_MODE]           = RENDER_RAW;
343 //#endif
344     eglSettings[CFG_VSYNC]          = 0;
345     eglSettings[CFG_FSAA]           = 0;
346     eglSettings[CFG_FPS]            = 0;
347     eglSettings[CFG_RED_SIZE]       = 5;
348     eglSettings[CFG_GREEN_SIZE]     = 6;
349     eglSettings[CFG_BLUE_SIZE]      = 5;
350     eglSettings[CFG_ALPHA_SIZE]     = 0;
351     eglSettings[CFG_DEPTH_SIZE]     = 16;
352     eglSettings[CFG_BUFFER_SIZE]    = 16;
353     eglSettings[CFG_STENCIL_SIZE]   = 0;
354
355     /* Parse INI file */
356     fp = fopen( file, "r");
357     if (fp != NULL)
358     {
359         while (fgets( buffer, MAX_SIZE, fp ) != NULL)
360         {
361             for (i=0; i<CFG_TOTAL; i++)
362             {
363                 location = strstr( buffer, eglStrings[i] );
364                 if (location != NULL)
365                 {
366                     eglSettings[i] = atol( location+strlen( eglStrings[i] ) );
367                     printf( "EGLport: %s set to %d.\n", eglStrings[i], eglSettings[i] );
368                     break;
369                 }
370             }
371         }
372
373         fclose( fp );
374     }
375     else
376     {
377         printf( "EGL NOTICE: Unable to read ini settings from file '%s'. Using defaults\n", file );
378     }
379 }
380
381 /** @brief Find a EGL configuration tht matches the defined attributes
382  * @return : 0 if the function passed, else 1
383  */
384 int8_t FindEGLConfigs( void )
385 {
386     EGLBoolean result;
387     int attrib = 0;
388     EGLint ConfigAttribs[23];
389
390     ConfigAttribs[attrib++] = EGL_RED_SIZE;                         /* 1 */
391     ConfigAttribs[attrib++] = eglSettings[CFG_RED_SIZE];            /* 2 */
392     ConfigAttribs[attrib++] = EGL_GREEN_SIZE;                       /* 3 */
393     ConfigAttribs[attrib++] = eglSettings[CFG_GREEN_SIZE];          /* 4 */
394     ConfigAttribs[attrib++] = EGL_BLUE_SIZE;                        /* 5 */
395     ConfigAttribs[attrib++] = eglSettings[CFG_BLUE_SIZE];           /* 6 */
396     ConfigAttribs[attrib++] = EGL_ALPHA_SIZE;                       /* 7 */
397     ConfigAttribs[attrib++] = eglSettings[CFG_ALPHA_SIZE];          /* 8 */
398     ConfigAttribs[attrib++] = EGL_DEPTH_SIZE;                       /* 9 */
399     ConfigAttribs[attrib++] = eglSettings[CFG_DEPTH_SIZE];          /* 10 */
400     ConfigAttribs[attrib++] = EGL_BUFFER_SIZE;                      /* 11 */
401     ConfigAttribs[attrib++] = eglSettings[CFG_BUFFER_SIZE];         /* 12 */
402     ConfigAttribs[attrib++] = EGL_STENCIL_SIZE;                     /* 13 */
403     ConfigAttribs[attrib++] = eglSettings[CFG_STENCIL_SIZE];        /* 14 */
404     ConfigAttribs[attrib++] = EGL_SURFACE_TYPE;                     /* 15 */
405     ConfigAttribs[attrib++] = EGL_WINDOW_BIT;                       /* 16 */
406 #if defined(EGL_VERSION_1_2)
407     ConfigAttribs[attrib++] = EGL_RENDERABLE_TYPE;                  /* 17 */
408 #if defined(USE_GLES1)
409     ConfigAttribs[attrib++] = EGL_OPENGL_ES_BIT;
410 #elif defined(USE_GLES2)
411     ConfigAttribs[attrib++] = EGL_OPENGL_ES2_BIT;                   /* 18 */
412 #endif /* USE_GLES1 */
413 #endif /* EGL_VERSION_1_2 */
414     ConfigAttribs[attrib++] = EGL_SAMPLE_BUFFERS;                   /* 19 */
415     ConfigAttribs[attrib++] = (eglSettings[CFG_FSAA] > 0) ? 1 : 0;  /* 20 */
416     ConfigAttribs[attrib++] = EGL_SAMPLES;                          /* 21 */
417     ConfigAttribs[attrib++] = eglSettings[CFG_FSAA];                /* 22 */
418     ConfigAttribs[attrib++] = EGL_NONE;                             /* 23 */
419
420     result = peglChooseConfig( eglDisplay, ConfigAttribs, eglConfigs, totalConfigsIn, &totalConfigsFound );
421     if (result != EGL_TRUE || totalConfigsFound == 0)
422     {
423         CheckEGLErrors( __FILE__, __LINE__ );
424         printf( "EGLport ERROR: Unable to query for available configs, found %d.\n", totalConfigsFound );
425         return 1;
426     }
427     printf( "EGLport: Found %d available configs\n", totalConfigsFound );
428
429     return 0;
430 }
431
432 /** @brief Error checking function
433  * @param file : string reference that contains the source file that the check is occuring in
434  * @param line : numeric reference that contains the line number that the check is occuring in
435  * @return : 0 if the function passed, else 1
436  */
437 int8_t CheckEGLErrors( const char* file, uint16_t line )
438 {
439     EGLenum error;
440     const char* errortext;
441     const char* description;
442
443     error = eglGetError();
444
445     if (error != EGL_SUCCESS && error != 0)
446     {
447         switch (error)
448         {
449             case EGL_NOT_INITIALIZED:
450                 errortext   = "EGL_NOT_INITIALIZED.";
451                 description = "EGL is not or could not be initialized, for the specified display.";
452                 break;
453             case EGL_BAD_ACCESS:
454                 errortext   = "EGL_BAD_ACCESS EGL";
455                 description = "cannot access a requested resource (for example, a context is bound in another thread).";
456                 break;
457             case EGL_BAD_ALLOC:
458                 errortext   = "EGL_BAD_ALLOC EGL";
459                 description = "failed to allocate resources for the requested operation.";
460                 break;
461             case EGL_BAD_ATTRIBUTE:
462                 errortext   = "EGL_BAD_ATTRIBUTE";
463                 description = "An unrecognized attribute or attribute value was passed in anattribute list.";
464                 break;
465             case EGL_BAD_CONFIG:
466                 errortext   = "EGL_BAD_CONFIG";
467                 description = "An EGLConfig argument does not name a valid EGLConfig.";
468                 break;
469             case EGL_BAD_CONTEXT:
470                 errortext   = "EGL_BAD_CONTEXT";
471                 description = "An EGLContext argument does not name a valid EGLContext.";
472                 break;
473             case EGL_BAD_CURRENT_SURFACE:
474                 errortext   = "EGL_BAD_CURRENT_SURFACE";
475                 description = "The current surface of the calling thread is a window, pbuffer,or pixmap that is no longer valid.";
476                 break;
477             case EGL_BAD_DISPLAY:
478                 errortext   = "EGL_BAD_DISPLAY";
479                 description = "An EGLDisplay argument does not name a valid EGLDisplay.";
480                 break;
481             case EGL_BAD_MATCH:
482                 errortext   = "EGL_BAD_MATCH";
483                 description = "Arguments are inconsistent; for example, an otherwise valid context requires buffers (e.g. depth or stencil) not allocated by an otherwise valid surface.";
484                 break;
485             case EGL_BAD_NATIVE_PIXMAP:
486                 errortext   = "EGL_BAD_NATIVE_PIXMAP";
487                 description = "An EGLNativePixmapType argument does not refer to a validnative pixmap.";
488                 break;
489             case EGL_BAD_NATIVE_WINDOW:
490                 errortext   = "EGL_BAD_NATIVE_WINDOW";
491                 description = "An EGLNativeWindowType argument does not refer to a validnative window.";
492                 break;
493             case EGL_BAD_PARAMETER:
494                 errortext   = "EGL_BAD_PARAMETER";
495                 description = "One or more argument values are invalid.";
496                 break;
497             case EGL_BAD_SURFACE:
498                 errortext   = "EGL_BAD_SURFACE";
499                 description = "An EGLSurface argument does not name a valid surface (window,pbuffer, or pixmap) configured for rendering";
500                 break;
501             case EGL_CONTEXT_LOST:
502                 errortext   = "EGL_CONTEXT_LOST";
503                 description = "A power management event has occurred. The application mustdestroy all contexts and reinitialise client API state and objects to continue rendering.";
504                 break;
505             default:
506                 errortext   = "Unknown EGL Error";
507                 description = "";
508                 break;
509         }
510
511         printf( "EGLport ERROR: EGL Error detected in file %s at line %d: %s (0x%X)\n  Description: %s\n", file, line, errortext, error, description );
512         return 1;
513     }
514
515     return 0;
516 }
517
518 #if 0
519
520 /** @brief Obtain a reference to the system's native display
521  * @param window : pointer to save the display reference
522  * @return : 0 if the function passed, else 1
523  */
524 int8_t GetNativeDisplay( void )
525 {
526     if (eglSettings[CFG_MODE] == RENDER_RAW)        /* RAW FB mode */
527     {
528         printf( "EGLport: Using EGL_DEFAULT_DISPLAY\n" );
529         nativeDisplay = EGL_DEFAULT_DISPLAY;
530     }
531     else if (eglSettings[CFG_MODE] == RENDER_SDL)   /* SDL/X11 mode */
532     {
533 #if defined(USE_EGL_SDL)
534         printf( "EGLport: Opening SDL/X11 display\n" );
535         SDL_VERSION(&sysWmInfo.version);
536         SDL_GetWMInfo(&sysWmInfo);
537         nativeDisplay = (EGLNativeDisplayType)sysWmInfo.info.x11.display;
538
539         if (nativeDisplay == 0)
540         {
541             printf( "EGLport ERROR: unable to get display!\n" );
542             return 1;
543         }
544 #else
545         printf( "EGLport ERROR: SDL mode was not enabled in this compile!\n" );
546 #endif
547     }
548
549     return 0;
550 }
551
552 /** @brief Obtain a reference to the system's native window
553  * @param width : desired pixel width of the window (not used by all platforms)
554  * @param height : desired pixel height of the window (not used by all platforms)
555  * @return : 0 if the function passed, else 1
556  */
557 int8_t GetNativeWindow( uint16_t width, uint16_t height )
558 {
559     nativeWindow = 0;
560
561 #if defined(WIZ) || defined(CAANOO)
562
563     nativeWindow = (NativeWindowType)malloc(16*1024);
564
565     if(nativeWindow == NULL) {
566         printf( "EGLport ERROR: Memory for window Failed\n" );
567         return 1;
568     }
569
570 #elif defined(RPI)
571
572     EGLBoolean result;
573     uint32_t screen_width, screen_height;
574     static EGL_DISPMANX_WINDOW_T nativewindow;
575     DISPMANX_ELEMENT_HANDLE_T dispman_element;
576     DISPMANX_DISPLAY_HANDLE_T dispman_display;
577     DISPMANX_UPDATE_HANDLE_T dispman_update;
578     VC_RECT_T dst_rect;
579     VC_RECT_T src_rect;
580
581     /* create an EGL window surface */
582     result = graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height);
583     if(result < 0) {
584         printf( "EGLport ERROR: RPi graphicget_display_size failed\n" );
585         return 1;
586     }
587
588     dst_rect.x = 0;
589     dst_rect.y = 0;
590     dst_rect.width = screen_width;
591     dst_rect.height = screen_height;
592
593     src_rect.x = 0;
594     src_rect.y = 0;
595     src_rect.width = width << 16;
596     src_rect.height = height << 16;
597
598     dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
599     dispman_update  = vc_dispmanx_update_start( 0 );
600     dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
601       0 /*layer*/, &dst_rect, 0 /*src*/,
602       &src_rect, DISPMANX_PROTECTION_NONE,  (VC_DISPMANX_ALPHA_T*)0 /*alpha*/,  (DISPMANX_CLAMP_T*)0 /*clamp*/,  (DISPMANX_TRANSFORM_T)0 /*transform*/);
603
604     nativewindow.element = dispman_element;
605     nativewindow.width = screen_width;
606     nativewindow.height = screen_height;
607     vc_dispmanx_update_submit_sync( dispman_update );
608
609     nativeWindow = (NativeWindowType)&nativewindow;
610
611 #else /* default */
612
613     if (eglSettings[CFG_MODE] == RENDER_RAW)        /* RAW FB mode */
614     {
615         nativeWindow = 0;
616     }
617     else if(eglSettings[CFG_MODE] == RENDER_SDL)    /* SDL/X11 mode */
618     {
619 #if defined(USE_EGL_SDL)
620         /* SDL_GetWMInfo is populated when display was opened */
621         nativeWindow = (NativeWindowType)sysWmInfo.info.x11.window;
622
623         if (nativeWindow == 0)
624         {
625             printf( "EGLport ERROR: unable to get window!\n" );
626             return 1;
627         }
628 #else
629         printf( "EGLport ERROR: SDL mode was not enabled in this compile!\n" );
630 #endif
631     }
632     else
633     {
634         printf( "EGLport ERROR: Unknown EGL render mode %d!\n", eglSettings[CFG_MODE] );
635         return 1;
636     }
637
638 #endif /* WIZ / CAANOO */
639
640     return 0;
641 }
642
643 #else
644
645 #include <xf86drm.h>
646 #include <xf86drmMode.h>
647 #include <gbm.h>
648 #include <errno.h>
649
650 static struct {
651     struct gbm_device *dev;
652     struct gbm_surface *surface;
653 } gbm;
654
655 static struct {
656     int fd;
657     uint32_t crtc_id;
658     uint32_t connector_id;
659     //struct gbm_bo *bo;
660 } drm;
661
662 int8_t GetNativeDisplay( void )
663 {
664     drmModeRes *resources;
665     drmModeConnector *connector;
666     drmModeEncoder *encoder;
667     drmModeCrtc *crtc;
668     int i;
669
670     errno = 0;
671
672     /* init drm */
673     drm.fd = drmOpen("omapdrm", NULL);
674     if (drm.fd < 0) {
675         perror("DRM: drmOpen omapdrm");
676         exit(1);
677     }
678
679     resources = drmModeGetResources(drm.fd);
680     if (resources == NULL) {
681         perror("DRM: drmModeGetResources");
682         exit(1);
683     }
684
685     /* find a connected connector: */
686     for (i = 0; i < resources->count_connectors; i++) {
687         connector = drmModeGetConnector(drm.fd, resources->connectors[i]);
688         if (connector->connection == DRM_MODE_CONNECTED)
689             break;
690         drmModeFreeConnector(connector);
691         connector = NULL;
692     }
693
694     if (connector == NULL) {
695         fprintf(stderr, "DRM: no connected connector\n");
696         exit(1);
697     }
698
699     encoder = drmModeGetEncoder(drm.fd, connector->encoder_id);
700     if (encoder == NULL) {
701         fprintf(stderr, "DRM: drmModeGetEncoder failed\n");
702         exit(1);
703     }
704
705     crtc = drmModeGetCrtc(drm.fd, encoder->crtc_id);
706     if (crtc == NULL) {
707         fprintf(stderr, "DRM: drmModeGetCrtc failed\n");
708         exit(1);
709     }
710
711     drm.crtc_id = encoder->crtc_id;
712     drm.connector_id = connector->connector_id;
713
714     /* init gbm */
715     gbm.dev = gbm_create_device(drm.fd);
716     if (gbm.dev == NULL) {
717         fprintf(stderr, "DRM: gbm_create_device failed\n");
718         exit(1);
719     }
720
721     gbm.surface = gbm_surface_create(gbm.dev,
722             crtc->width, crtc->height,
723             GBM_FORMAT_XRGB8888,
724             GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
725     if (!gbm.surface) {
726         fprintf(stderr, "DRM: failed to create gbm surface\n");
727         exit(1);
728     }
729
730     nativeDisplay = (EGLNativeDisplayType)gbm.dev;
731     nativeWindow = (NativeWindowType)gbm.surface;
732
733 #if 0
734     drm.bo = gbm_surface_lock_front_buffer(gbm.surface);
735     if (drm.bo == NULL) {
736         fprintf(stderr, "DRM: no initial bo?\n");
737         exit(1);
738     }
739 #endif
740
741     //ret = drmModeSetCrtc(drm.fd, drm.crtc_id, fb->fb_id, 0, 0,
742     //       &drm.connector_id, 1, drm.mode);
743
744     return 0;
745 }
746
747 int8_t GetNativeWindow( uint16_t width, uint16_t height )
748 {
749     /* already have nativeWindow, ignore width, height */
750     return 0;
751 }
752
753 static void
754 drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
755 {
756     uint32_t fb_id = (uint32_t)(long)data;
757
758     if (fb_id)
759         drmModeRmFB(drm.fd, fb_id);
760 }
761
762 static uint32_t drm_fb_get_from_bo(struct gbm_bo *bo)
763 {
764     uint32_t fb_id = (uint32_t)(long)gbm_bo_get_user_data(bo);
765     uint32_t width, height, stride, handle;
766     int ret;
767
768     if (fb_id)
769         return fb_id;
770
771     width = gbm_bo_get_width(bo);
772     height = gbm_bo_get_height(bo);
773     stride = gbm_bo_get_stride(bo);
774     handle = gbm_bo_get_handle(bo).u32;
775
776     ret = drmModeAddFB(drm.fd, width, height, 24, 32, stride, handle, &fb_id);
777     if (ret) {
778         printf("failed to create fb: %s\n", strerror(errno));
779         return 0;
780     }
781
782     gbm_bo_set_user_data(bo, (void *)(long)fb_id, drm_fb_destroy_callback);
783
784     return fb_id;
785 }
786
787 static void page_flip_handler(int fd, unsigned int frame,
788     unsigned int sec, unsigned int usec, void *data)
789 {
790     int *waiting_for_flip = (int *)data;
791     *waiting_for_flip = 0;
792 }
793
794 /* to be called after eglSwapBuffers */
795 static void drm_do_swap(void)
796 {
797     drmEventContext evctx = { 0, };
798     int waiting_for_flip = 1;
799     struct gbm_bo *bo;
800     uint32_t fb_id;
801     fd_set fds;
802     int ret;
803
804     bo = gbm_surface_lock_front_buffer(gbm.surface);
805     fb_id = drm_fb_get_from_bo(bo);
806
807     ret = drmModePageFlip(drm.fd, drm.crtc_id, fb_id,
808             DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
809     if (ret)
810         fprintf(stderr, "page flip error: %d %d\n", ret, errno);
811
812     FD_ZERO(&fds);
813     //FD_SET(0, &fds);
814     FD_SET(drm.fd, &fds);
815
816     evctx.version = DRM_EVENT_CONTEXT_VERSION;
817     evctx.page_flip_handler = page_flip_handler;
818
819     while (waiting_for_flip) {
820         ret = select(drm.fd + 1, &fds, NULL, NULL, NULL);
821         if (ret <= 0) {
822             perror("select");
823             return;
824 #if 0
825         } else if (FD_ISSET(0, &fds)) {
826             printf("user interrupted!\n");
827             exit(1); // ?
828 #endif
829         }
830         drmHandleEvent(drm.fd, &evctx);
831     }
832
833     gbm_surface_release_buffer(gbm.surface, bo);
834 }
835
836 #endif
837
838 /** @brief Release the system's native display
839  */
840 void FreeNativeDisplay( void )
841 {
842 }
843
844 /** @brief Release the system's native window
845  */
846 void FreeNativeWindow( void )
847 {
848 #if defined(WIZ) || defined(CAANOO)
849     if (nativeWindow != NULL) {
850         free( nativeWindow );
851     }
852     nativeWindow = NULL;
853 #endif /* WIZ / CAANOO */
854 }
855
856 /** @brief Open any system specific resources
857  */
858 void Platform_Open( void )
859 {
860 #if defined(PANDORA)
861     /* Pandora VSync */
862     fbdev = open( "/dev/fb0", O_RDONLY /* O_RDWR */ );
863     if ( fbdev < 0 ) {
864         printf( "EGLport ERROR: Couldn't open /dev/fb0 for Pandora Vsync\n" );
865     }
866 #elif defined(RPI)
867     bcm_host_init();
868 #endif /* PANDORA */
869 }
870
871 /** @brief Release any system specific resources
872  */
873 void Platform_Close( void )
874 {
875 #if defined(PANDORA)
876     /* Pandora VSync */
877     close( fbdev );
878     fbdev = -1;
879 #endif /* PANDORA */
880 }
881
882 /** @brief Check the systems vsync state
883  */
884 void Platform_VSync( void )
885 {
886 #if defined(PANDORA)
887     /* Pandora VSync */
888     if (fbdev >= 0) {
889         int arg = 0;
890         ioctl( fbdev, FBIO_WAITFORVSYNC, &arg );
891     }
892 #endif /* PANDORA */
893 }
894
895 /** @brief Get the system tick time (ms)
896  */
897 uint32_t Platform_GetTicks( void )
898 {
899     uint32_t ticks = 0;
900 #if defined(USE_EGL_SDL)
901     ticks = SDL_GetTicks();
902 #else
903     printf( "EGLport ERROR: SDL mode was not enabled in this compile!\n" );
904 #endif
905     return ticks;
906 }
907
908 // vim:ts=4:sw=4:expandtab