451ab91e |
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 | |
daa7f9a3 |
112 | static void drm_do_swap(void); |
113 | |
451ab91e |
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 ); |
daa7f9a3 |
158 | drm_do_swap(); |
451ab91e |
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 */ |
06190a2d |
339 | //#if defined(USE_EGL_SDL) |
340 | // eglSettings[CFG_MODE] = RENDER_SDL; |
341 | //#else |
451ab91e |
342 | eglSettings[CFG_MODE] = RENDER_RAW; |
06190a2d |
343 | //#endif |
451ab91e |
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 | { |
06190a2d |
377 | printf( "EGL NOTICE: Unable to read ini settings from file '%s'. Using defaults\n", file ); |
451ab91e |
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 | |
daa7f9a3 |
518 | #if 0 |
519 | |
451ab91e |
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 | |
daa7f9a3 |
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 | |
451ab91e |
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 | } |
daa7f9a3 |
907 | |
908 | // vim:ts=4:sw=4:expandtab |