GCC Code Coverage Report


Directory: src/gate/
File: src/gate/graphics/platform/opengl_xlib_impl.h
Date: 2026-06-21 00:38:37
Exec Total Coverage
Lines: 0 447 0.0%
Functions: 0 20 0.0%
Branches: 0 205 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2026, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28 #ifndef GATE_GRAPHICS_PLATFORM_OPENGL_XLIB_IMPL_H_INCLUDED
29 #define GATE_GRAPHICS_PLATFORM_OPENGL_XLIB_IMPL_H_INCLUDED
30
31 #include "gate/platform/posix/xlib.h"
32 #include "gate/graphics/gl_apis.h"
33 #include "gate/graphics/platform/opengl_apis.h"
34 #include "gate/graphics/platform/opengl_egl_apis.h"
35 #include "gate/threading.h"
36 #include "gate/debugging.h"
37 #include <GL/glx.h>
38
39 typedef struct gate_glx
40 {
41 XVisualInfo* (*glXChooseVisual)(Display* dpy, int screen, int* attribList);
42 } gate_glx_t;
43
44 static gate_glx_t glx = GATE_INIT_EMPTY;
45 static gate_bool_t volatile glx_loaded = false;
46
47 static gate_result_t gate_glx_load_functions(void)
48 {
49 static gate_string_t glx_lib_name = GATE_STRING_INIT_STATIC("libGL.so");
50 gate_result_t ret = GATE_RESULT_FAILED;
51 static gate_library_t glx_lib = NULL;
52
53 do
54 {
55 if (glx_loaded)
56 {
57 ret = GATE_RESULT_OK;
58 break;
59 }
60
61 if (glx_lib == NULL)
62 {
63 ret = gate_library_open(&glx_lib_name, &glx_lib, GATE_LIBRARY_FLAG_DEFAULT);
64 GATE_BREAK_IF_FAILED(ret);
65 }
66
67 GATE_BREAK_IF_FAILED(ret = gate_library_get_function_name(glx_lib, "glXChooseVisual", &glx.glXChooseVisual));
68
69 glx_loaded = true;
70 ret = GATE_RESULT_OK;
71 } while (0);
72 return ret;
73 }
74
75
76 typedef struct gate_xlib_handle
77 {
78 Display* display; /**< x11 display connection */
79 Window root_win; /**< x11 root window handle */
80 Window surface_win; /**< x11 surface window handle */
81 int cancel_events; /**< exit x11 event loop */
82 Atom wm_protocols; /**< x11 client-message WM_PROTOCOL atom */
83 Atom wm_delete_window; /**< x11 WM_PROTOCOL data for delete-window message -> close button */
84 } gate_xlib_handle_t;
85
86 static int default_xlib_visual_attribs_doublebuffer[] =
87 {
88 GLX_RGBA,
89 GLX_DOUBLEBUFFER,
90 GLX_RED_SIZE, 4,
91 GLX_GREEN_SIZE, 4,
92 GLX_BLUE_SIZE, 4,
93 GLX_DEPTH_SIZE, 16,
94 None
95 };
96 static int default_xlib_visual_attribs_singlebuffer[] =
97 {
98 GLX_RGBA,
99 GLX_RED_SIZE, 4,
100 GLX_GREEN_SIZE, 4,
101 GLX_BLUE_SIZE, 4,
102 GLX_DEPTH_SIZE, 16,
103 None
104 };
105
106 static void gate_xlib_surface_destroy(void* xlib_surface)
107 {
108 gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface;
109 if (xhandle->surface_win)
110 {
111 xlib.XDestroyWindow(xhandle->display, xhandle->surface_win);
112 }
113 if (xhandle->display)
114 {
115 xlib.XCloseDisplay(xhandle->display);
116 }
117 gate_mem_dealloc(xhandle);
118 }
119
120 void* gate_xlib_surface_create(gate_int32_t x, gate_int32_t y, gate_uint32_t width, gate_uint32_t height)
121 {
122 gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)gate_mem_alloc(sizeof(gate_xlib_handle_t));
123 gate_bool_t completed = false;
124 int xdefaultscreen;
125 XVisualInfo visualinfo;
126 XVisualInfo* vi;
127 XWindowAttributes windowattrs;
128
129
130 if (xhandle == NULL)
131 {
132 return NULL;
133 }
134
135 xhandle->display = NULL;
136 xhandle->root_win = 0;
137 xhandle->surface_win = 0;
138 xhandle->cancel_events = 0;
139
140 do
141 {
142 xhandle->display = xlib.XOpenDisplay(NULL);
143 if (xhandle->display == NULL)
144 {
145 xhandle->display = xlib.XOpenDisplay(":0");
146 }
147 if (xhandle->display == NULL)
148 {
149 GATE_DEBUG_TRACE("XOpenDisplay() failed");
150 break;
151 }
152 xhandle->root_win = xlib.XDefaultRootWindow(xhandle->display);
153 xdefaultscreen = xlib.XDefaultScreen(xhandle->display);
154
155 gate_mem_clear(&visualinfo, sizeof(visualinfo));
156
157 if (glx.glXChooseVisual)
158 {
159 vi = glx.glXChooseVisual(xhandle->display, xdefaultscreen, default_xlib_visual_attribs_doublebuffer);
160 if (vi == NULL)
161 {
162 vi = glx.glXChooseVisual(xhandle->display, xdefaultscreen, default_xlib_visual_attribs_singlebuffer);
163 }
164 if (vi == NULL)
165 {
166 GATE_DEBUG_TRACE("glXChooseVisual() failed");
167 break;
168 }
169 visualinfo = *vi;
170 }
171 else
172 {
173 xlib.XMatchVisualInfo(xhandle->display, xdefaultscreen, 16, TrueColor, &visualinfo);
174 }
175
176
177 XSetWindowAttributes swa;
178 gate_mem_clear(&swa, sizeof(swa));
179 swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;
180 swa.background_pixel = 0;
181 swa.border_pixel = 0;
182 swa.colormap = xlib.XCreateColormap(xhandle->display, xhandle->root_win, visualinfo.visual, AllocNone);
183
184 if ((width == 0) || (height == 0))
185 {
186 xlib.XGetWindowAttributes(xhandle->display, xhandle->root_win, &windowattrs);
187 if (width == 0)
188 {
189 width = windowattrs.width;
190 }
191 if (height == 0)
192 {
193 height = windowattrs.height;
194 }
195 }
196
197 xhandle->surface_win = xlib.XCreateWindow(xhandle->display, xhandle->root_win,
198 x, y, width, height, 0,
199 /*CopyFromParent*/ visualinfo.depth,
200 InputOutput,
201 /*CopyFromParent*/ visualinfo.visual,
202 CWEventMask | CWBackPixel | CWBorderPixel | CWColormap,
203 &swa);
204
205 xhandle->wm_protocols = xlib.XInternAtom(xhandle->display, "WM_PROTOCOLS", False);
206 xhandle->wm_delete_window = xlib.XInternAtom(xhandle->display, "WM_DELETE_WINDOW", False);
207 xlib.XSetWMProtocols(xhandle->display, xhandle->surface_win, &xhandle->wm_delete_window, 1);
208
209 xlib.XMapWindow(xhandle->display, xhandle->surface_win);
210 xlib.XFlush(xhandle->display);
211
212 completed = true;
213 } while (0);
214
215 if (!completed)
216 {
217 gate_xlib_surface_destroy(xhandle);
218 return NULL;
219 }
220 return xhandle;
221 }
222
223 static void gate_xlib_surface_resize(void* xlib_surface, gate_uint32_t width, gate_uint32_t height)
224 {
225 gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface;
226 xlib.XResizeWindow(xhandle->display, xhandle->surface_win, width, height);
227 /* TODO */
228 }
229 static void gate_xlib_surface_get_client_size(void* xlib_surface, gate_uint32_t* ptr_width, gate_uint32_t* ptr_height)
230 {
231 gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface;
232 XWindowAttributes windowattrs = GATE_INIT_EMPTY;
233 xlib.XGetWindowAttributes(xhandle->display, xhandle->surface_win, &windowattrs);
234 if (ptr_width)
235 {
236 *ptr_width = windowattrs.width;
237 }
238 if (ptr_height)
239 {
240 *ptr_height = windowattrs.height;
241 }
242 }
243
244 static void* gate_xlib_surface_get_handle(void* xlib_surface)
245 {
246 gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface;
247 return (void*)xhandle->surface_win;
248 }
249
250 static void gate_xlib_surface_handle_events(gate_gl_surface_t* gl_surface, gate_gl_surface_events_t* callbacks, void* user_param)
251 {
252 gate_xlib_handle_t* const xhandle = (gate_xlib_handle_t*)gl_surface->special_resources[0];
253
254 static const long mask = FocusChangeMask | PropertyChangeMask
255 | KeyPressMask | KeyReleaseMask | KeymapStateMask
256 | ButtonPressMask | ButtonReleaseMask /* | PointerMotionMask | PointerMotionHintMask */
257 | ExposureMask | VisibilityChangeMask
258 | StructureNotifyMask | SubstructureNotifyMask
259 ;
260
261
262 XEvent xevent;
263 KeySym keysym;
264 gate_input_keycode_t keycode;
265 gate_input_keystates_t keystates;
266 gate_bool_t skip_rendering = false;
267 static const gate_uint32_t no_event_loop_delay_min = 5;
268 static const gate_uint32_t no_event_loop_delay_max = 50;
269 gate_uint32_t no_event_loop_delay = no_event_loop_delay_min;
270
271 if (callbacks->on_resize)
272 {
273 gate_uint32_t width, height;
274 gate_gl_surface_get_size(gl_surface, &width, &height);
275 callbacks->on_resize(gl_surface,
276 width, height,
277 user_param);
278 }
279
280 xlib.XAutoRepeatOff(xhandle->display);
281 xlib.XSelectInput(xhandle->display, xhandle->surface_win, mask);
282 for (;;)
283 {
284 if (xhandle->cancel_events)
285 {
286 xhandle->cancel_events = 0;
287 break;
288 }
289 if (!skip_rendering && callbacks)
290 {
291 if (callbacks->on_render)
292 {
293 callbacks->on_render(gl_surface, user_param);
294 }
295 }
296 /*
297 if(!xlib.XCheckMaskEvent(xhandle->display, mask, &xevent))
298 {
299 gate_thread_sleep(10);
300 }
301 else
302 {
303 */
304 skip_rendering = false;
305 if (xlib.XPending(xhandle->display) <= 0)
306 {
307 gate_thread_sleep(no_event_loop_delay);
308 if (no_event_loop_delay < no_event_loop_delay_max)
309 {
310 ++no_event_loop_delay;
311 }
312 }
313 else
314 {
315 no_event_loop_delay = no_event_loop_delay_min;
316 gate_mem_clear(&xevent, sizeof(xevent));
317 xlib.XNextEvent(xhandle->display, &xevent);
318
319 if (callbacks && (xevent.xany.window == xhandle->surface_win))
320 {
321 switch (xevent.type)
322 {
323 case ConfigureNotify:
324 {
325 if (callbacks->on_resize)
326 {
327 callbacks->on_resize(gl_surface,
328 xevent.xconfigure.width,
329 xevent.xconfigure.height,
330 user_param);
331 }
332 break;
333 }
334 case KeyPress:
335 {
336 if (callbacks->on_key_down)
337 {
338 gate_bool_t have_keycode = false;
339 keysym = xlib.XLookupKeysym(&xevent.xkey, 0);
340 keycode = 0;
341 keystates = 0;
342 if (xevent.xkey.state & ShiftMask)
343 {
344 keystates |= GATE_KBD_KEYSTATE_SHIFT;
345 }
346 if (xevent.xkey.state & LockMask)
347 {
348 keystates |= GATE_KBD_KEYSTATE_MENU;
349 }
350 if (xevent.xkey.state & ControlMask)
351 {
352 keystates |= GATE_KBD_KEYSTATE_CTRL;
353 }
354
355 have_keycode = gate_xlib_convert_keysym(keysym, &keycode);
356 if(have_keycode)
357 {
358 callbacks->on_key_down(gl_surface, keycode, keystates, user_param);
359 }
360 }
361 break;
362 }
363 case KeyRelease:
364 {
365 if (callbacks->on_key_up)
366 {
367 gate_bool_t have_keycode = false;
368 keysym = xlib.XLookupKeysym(&xevent.xkey, 0);
369 keycode = 0;
370 keystates = 0;
371 if (xevent.xkey.state & ShiftMask)
372 {
373 keystates |= GATE_KBD_KEYSTATE_SHIFT;
374 }
375 if (xevent.xkey.state & LockMask)
376 {
377 keystates |= GATE_KBD_KEYSTATE_MENU;
378 }
379 if (xevent.xkey.state & ControlMask)
380 {
381 keystates |= GATE_KBD_KEYSTATE_CTRL;
382 }
383 have_keycode = gate_xlib_convert_keysym(keysym, &keycode);
384 if (have_keycode)
385 {
386 callbacks->on_key_up(gl_surface, keycode, keystates, user_param);
387 }
388 }
389 break;
390 }
391 case ButtonPress:
392 {
393 if (callbacks->on_pointer_down)
394 {
395 callbacks->on_pointer_down(gl_surface, xevent.xbutton.button,
396 xevent.xbutton.x, xevent.xbutton.y, user_param);
397 }
398 break;
399 }
400 case ButtonRelease:
401 {
402 if (callbacks->on_pointer_up)
403 {
404 callbacks->on_pointer_up(gl_surface, xevent.xbutton.button,
405 xevent.xbutton.x, xevent.xbutton.y, user_param);
406 }
407 break;
408 }
409 case ClientMessage:
410 {
411 if (xevent.xclient.message_type == xhandle->wm_protocols)
412 {
413 if (xevent.xclient.data.l[0] == (long)xhandle->wm_delete_window)
414 {
415 if (callbacks->on_exit)
416 {
417 callbacks->on_exit(gl_surface, user_param);
418 }
419 break;
420 }
421 }
422 break;
423 }
424 default:
425 {
426 skip_rendering = true;
427 break;
428 }
429 }
430 }
431 }
432 } /* for loop */
433 xlib.XAutoRepeatOn(xhandle->display);
434 }
435 static void gate_xlib_surface_cancel_events(void* xlib_surface)
436 {
437 gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface;
438 if (xhandle)
439 {
440 xhandle->cancel_events = 1;
441 }
442 }
443
444
445
446
447 gate_result_t gate_gl_surface_init(gate_gl_surface_t* surface)
448 {
449 gate_result_t ret;
450 do
451 {
452 ret = gate_xlib_load_functions();
453 GATE_BREAK_IF_FAILED(ret);
454 ret = gate_egl_load_functions();
455 GATE_BREAK_IF_FAILED(ret);
456 ret = gate_gl_api_load_functions();
457 GATE_BREAK_IF_FAILED(ret);
458 ret = gate_glx_load_functions();
459 GATE_BREAK_IF_FAILED(ret);
460 #if defined(GATE_GRAPHICS_OPENGL2_SUPPORT)
461 ret = gate_gl2_api_load_functions();
462 GATE_BREAK_IF_FAILED(ret);
463 #endif
464 gate_mem_clear(surface, sizeof(gate_gl_surface_t));
465 } while (0);
466
467 return ret;
468 }
469 gate_result_t gate_gl_surface_uninit(gate_gl_surface_t* surface)
470 {
471 gate_mem_clear(surface, sizeof(gate_gl_surface_t));
472 return GATE_RESULT_OK;
473 }
474
475
476
477 static EGLint gate_egl_attribs_pbuffer[] =
478 {
479 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
480 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
481 //EGL_RED_SIZE, (EGLint)5,
482 //EGL_GREEN_SIZE, (EGLint)6,
483 //EGL_BLUE_SIZE, (EGLint)5,
484 //EGL_ALPHA_SIZE, (EGLint)0,
485 EGL_DEPTH_SIZE, (EGLint)16,
486 //EGL_STENCIL_SIZE, (EGLint)0,
487 EGL_NONE
488 };
489
490 static EGLint gate_egl_attribs_window[] =
491 {
492 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
493 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
494 EGL_RED_SIZE, (EGLint)5,
495 EGL_GREEN_SIZE, (EGLint)5,
496 EGL_BLUE_SIZE, (EGLint)5,
497 EGL_ALPHA_SIZE, (EGLint)0,
498 EGL_DEPTH_SIZE, (EGLint)16,
499 //EGL_STENCIL_SIZE, (EGLint)0,
500 EGL_NONE
501 };
502
503 static gate_bool_t create_egl_context_from_configs(EGLDisplay egl_display, EGLConfig* configs, gate_size_t configs_count, EGLint const* context_attribs,
504 EGLContext* ptr_found_context, EGLint* ptr_used_config_index)
505 {
506 gate_size_t ndx;
507 for (ndx = 0; ndx < configs_count; ++ndx)
508 {
509 EGLContext egl_ctx = egl.CreateContext(egl_display, configs[ndx], EGL_NO_CONTEXT, context_attribs);
510 if (egl_ctx != EGL_NO_CONTEXT)
511 {
512 if (ptr_found_context)
513 {
514 *ptr_found_context = egl_ctx;
515 }
516 else
517 {
518 egl.DestroyContext(egl_display, egl_ctx);
519 }
520 if (ptr_used_config_index)
521 {
522 *ptr_used_config_index = ndx;
523 }
524 return true;
525 }
526 }
527 return false;
528 }
529
530 static EGLint context_egl1_attribs[] = {
531 EGL_CONTEXT_CLIENT_VERSION, 1,
532 EGL_NONE
533 };
534
535 static EGLint context_egl2_attribs[] = {
536 EGL_CONTEXT_CLIENT_VERSION, 2,
537 EGL_NONE
538 };
539
540
541 static gate_result_t gate_gl_surface_egl_prepare(EGLint const* egl_attrib_list, EGLDisplay* ptr_egl_display,
542 EGLContext* ptr_egl_context, EGLConfig* ptr_egl_config, unsigned* ptr_egl_version)
543 {
544 gate_result_t ret = GATE_RESULT_FAILED;
545 EGLDisplay egl_display = EGL_NO_DISPLAY;
546 EGLint egl_version_major, egl_version_minor;
547 int egl_configs = 0;
548 EGLConfig all_configs[64] = GATE_INIT_EMPTY;
549 EGLint all_configs_count = sizeof(all_configs) / sizeof(all_configs[0]);
550 EGLConfig egl_current_config[64] = GATE_INIT_EMPTY;
551 EGLint ndx;
552 EGLint egl_current_configs_count = sizeof(egl_current_config) / sizeof(egl_current_config[0]);
553 EGLContext egl_context = EGL_NO_CONTEXT;
554 EGLConfig* ptr_egl_current_config = NULL;
555
556
557 do
558 {
559 gate_bool_t const try_egl1_first = ptr_egl_version && (*ptr_egl_version < 2);
560 EGLint const* egl_attribs1 = try_egl1_first ? context_egl1_attribs : context_egl2_attribs;
561 EGLint const* egl_attribs2 = try_egl1_first ? context_egl2_attribs : context_egl1_attribs;
562 unsigned egl_result1 = try_egl1_first ? 1 : 2;
563 unsigned egl_result2 = try_egl1_first ? 2 : 1;
564
565
566
567 egl_display = egl.GetDisplay(EGL_DEFAULT_DISPLAY);
568 if (egl_display == EGL_NO_DISPLAY)
569 {
570 GATE_DEBUG_TRACE("eglGetDisplay() failed");
571 ret = GATE_RESULT_FAILED;
572 break;
573 }
574 if (EGL_FALSE == egl.Initialize(egl_display, &egl_version_major, &egl_version_minor))
575 {
576 GATE_DEBUG_TRACE("eglInitialize() failed");
577 ret = GATE_RESULT_FAILED;
578 break;
579 }
580 if (EGL_FALSE == egl.GetConfigs(egl_display, all_configs, all_configs_count, &egl_configs))
581 {
582 GATE_DEBUG_TRACE("eglGetConfigs() failed");
583 ret = GATE_RESULT_FAILED;
584 break;
585 }
586
587 if (EGL_FALSE == egl.ChooseConfig(egl_display, egl_attrib_list,
588 egl_current_config, egl_current_configs_count,
589 &egl_current_configs_count))
590 {
591 GATE_DEBUG_TRACE("eglChooseConfig() failed");
592 ret = GATE_RESULT_FAILED;
593 break;
594 }
595
596 if (egl_current_configs_count == 0)
597 {
598 GATE_DEBUG_TRACE("eglChooseConfig() failed");
599 ret = GATE_RESULT_FAILED;
600 break;
601 }
602
603 /* try first EGL version attributes */
604 if(create_egl_context_from_configs(egl_display, egl_current_config, egl_current_configs_count, egl_attribs1, &egl_context, &ndx))
605 {
606 /* first attempt succeeded */
607 ptr_egl_current_config = &egl_current_config[ndx];
608 if (ptr_egl_version)
609 {
610 *ptr_egl_version = egl_result1;
611 }
612 }
613 else
614 {
615 /* try alternative EGL version attributes */
616 if(create_egl_context_from_configs(egl_display, egl_current_config, egl_current_configs_count, egl_attribs2, &egl_context, &ndx))
617 {
618 /* second attempt succeeded */
619 ptr_egl_current_config = &egl_current_config[ndx];
620 if (ptr_egl_version)
621 {
622 *ptr_egl_version = egl_result2;
623 }
624 }
625 else
626 {
627 /* context creation failed */
628 egl_context = EGL_NO_CONTEXT;
629 }
630 }
631
632 if (egl_context == EGL_NO_CONTEXT)
633 {
634 EGLint egl_error = egl.GetError();
635 GATE_DEBUG_TRACE("eglCreateContext() failed");
636 GATE_DEBUG_TRACE_VALUE(egl_error);
637 ret = GATE_RESULT_OUTOFRESOURCES;
638 break;
639 }
640
641 *ptr_egl_display = egl_display;
642 *ptr_egl_context = egl_context;
643 gate_mem_copy(ptr_egl_config, ptr_egl_current_config, sizeof(EGLConfig));
644 egl_display = EGL_NO_DISPLAY;
645 egl_context = EGL_NO_DISPLAY;
646 ret = GATE_RESULT_OK;
647 } while (0);
648
649 if (egl_context != EGL_NO_CONTEXT)
650 {
651 egl.DestroyContext(egl_display, egl_context);
652 }
653
654 if (egl_display != EGL_NO_DISPLAY)
655 {
656 egl.Terminate(egl_display);
657 }
658
659 return ret;
660 }
661
662
663 gate_result_t gate_gl_surface_open(gate_gl_surface_t* surface, gate_gl_surface_type_t type,
664 gate_uint32_t width, gate_uint32_t height, gate_enumint_t flags)
665 {
666 gate_result_t ret = GATE_RESULT_FAILED;
667 EGLDisplay egl_display = EGL_NO_DISPLAY;
668 EGLContext egl_context = EGL_NO_CONTEXT;
669 EGLSurface egl_surface = EGL_NO_SURFACE;
670 void* xlib_surface = NULL;
671 NativeWindowType egl_native_window;
672 EGLConfig egl_config;
673 unsigned egl_version = 0;
674
675 EGLint gate_egl_pbuffer_surface_attribs[] =
676 {
677 EGL_WIDTH, (EGLint)width,
678 EGL_HEIGHT, (EGLint)height,
679 //EGL_COLORSPACE, (EGLint)GL_RGBA,
680 //EGL_TEXTURE_FORMAT, (EGLint)EGL_TEXTURE_RGB,
681 //EGL_TEXTURE_TARGET, (EGLint)EGL_TEXTURE_2D,
682 EGL_LARGEST_PBUFFER, (EGLint)EGL_TRUE,
683 EGL_NONE
684 };
685
686 do
687 {
688 switch (type)
689 {
690 case gate_gl_surface_type_external:
691 {
692 break;
693 }
694 case gate_gl_surface_type_screen:
695 {
696 xlib_surface = gate_xlib_surface_create(0, 0, width, height);
697 if (xlib_surface == NULL)
698 {
699 GATE_DEBUG_TRACE("gate_xlib_surface_create() failed");
700 ret = GATE_RESULT_OUTOFRESOURCES;
701 break;
702 }
703
704 egl_version = 2;
705 ret = gate_gl_surface_egl_prepare(gate_egl_attribs_window, &egl_display, &egl_context, &egl_config, &egl_version);
706 GATE_BREAK_IF_FAILED(ret);
707
708
709 egl_native_window = (NativeWindowType)gate_xlib_surface_get_handle(xlib_surface);
710
711 egl_surface = egl.CreateWindowSurface(egl_display, egl_config, egl_native_window, NULL);
712 if (egl_surface == EGL_NO_SURFACE)
713 {
714 GATE_DEBUG_TRACE("eglCreateWindowSurface() failed");
715 ret = GATE_RESULT_OUTOFRESOURCES;
716 break;
717 }
718
719 gate_xlib_surface_get_client_size(xlib_surface, &width, &height);
720
721 gate_gl_api.glViewport(0, 0, width, height);
722
723 ret = GATE_RESULT_OK;
724 break;
725 }
726 case gate_gl_surface_type_image:
727 {
728 ret = gate_gl_surface_egl_prepare(gate_egl_attribs_pbuffer, &egl_display, &egl_context, &egl_config, &egl_version);
729 GATE_BREAK_IF_FAILED(ret);
730
731 egl_surface = egl.CreatePbufferSurface(egl_display, egl_config, gate_egl_pbuffer_surface_attribs);
732 if (egl_surface == EGL_NO_SURFACE)
733 {
734 GATE_DEBUG_TRACE("eglCreateWindowSurface() failed");
735 ret = GATE_RESULT_OUTOFRESOURCES;
736 break;
737 }
738
739 ret = GATE_RESULT_OK;
740 break;
741 }
742 default:
743 {
744 return GATE_RESULT_NOTSUPPORTED;
745 }
746 }
747
748 GATE_BREAK_IF_FAILED(ret);
749
750 if (EGL_FALSE == egl.MakeCurrent(egl_display, egl_surface, egl_surface, egl_context))
751 {
752 GATE_DEBUG_TRACE("eglMakeCurrent() failed");
753 ret = GATE_RESULT_INVALIDSTATE;
754 break;
755 }
756
757
758 surface->surface_type = type;
759 surface->width = width;
760 surface->height = height;
761 surface->native_surface = (void*)egl_surface;
762 surface->native_context = (void*)egl_context;
763 surface->special_resources[0] = (void*)xlib_surface; /* gate_xlib_handle */
764 surface->special_resources[1] = (void*)egl_display;
765 surface->special_resources[2] = (void*)(gate_uintptr_t)egl_version;
766 surface->event_handler = NULL;
767 surface->event_handler_param = NULL;
768
769 egl_surface = EGL_NO_SURFACE;
770 egl_context = EGL_NO_CONTEXT;
771 egl_display = EGL_NO_DISPLAY;
772 xlib_surface = NULL;
773
774 } while (0);
775
776 if (egl_surface != EGL_NO_SURFACE)
777 {
778 egl.DestroySurface(egl_display, egl_surface);
779 }
780
781 if (xlib_surface != NULL)
782 {
783 gate_xlib_surface_destroy(xlib_surface);
784 }
785
786 if (egl_context != EGL_NO_CONTEXT)
787 {
788 egl.DestroyContext(egl_display, egl_context);
789 }
790
791 if (egl_display != EGL_NO_DISPLAY)
792 {
793 egl.Terminate(egl_display);
794 }
795
796 return ret;
797 }
798 gate_result_t gate_gl_surface_close(gate_gl_surface_t* surface)
799 {
800 gate_result_t ret = GATE_RESULT_FAILED;
801 EGLDisplay egl_display = EGL_NO_DISPLAY;
802 EGLSurface egl_surface = EGL_NO_SURFACE;
803 EGLContext egl_context = EGL_NO_CONTEXT;
804 gate_xlib_handle_t* xlib_handle = NULL;
805
806 do
807 {
808 if (surface->surface_type == gate_gl_surface_type_external)
809 {
810 gate_mem_clear(surface, sizeof(gate_gl_surface_t));
811 ret = GATE_RESULT_OK;
812 break;
813 }
814
815 egl_surface = (EGLSurface)surface->native_surface;
816 egl_context = (EGLContext)surface->native_context;
817 xlib_handle = (gate_xlib_handle_t*)surface->special_resources[0];
818 egl_display = (EGLDisplay)surface->special_resources[1];
819
820 egl.MakeCurrent(egl_display, NULL, NULL, EGL_NO_CONTEXT);
821 egl.DestroySurface(egl_display, egl_surface);
822 egl.DestroyContext(egl_display, egl_context);
823
824 if (xlib_handle)
825 {
826 gate_xlib_surface_destroy(xlib_handle);
827 }
828
829 gate_mem_clear(surface, sizeof(gate_gl_surface_t));
830 ret = GATE_RESULT_OK;
831 } while (0);
832
833 return ret;
834 }
835
836 gate_result_t gate_gl_surface_resize(gate_gl_surface_t* surface, gate_uint32_t width, gate_uint32_t height)
837 {
838 gate_result_t ret = GATE_RESULT_FAILED;
839 EGLDisplay egl_display = EGL_NO_DISPLAY;
840 EGLSurface egl_surface = EGL_NO_SURFACE;
841 EGLContext egl_context = EGL_NO_CONTEXT;
842 gate_xlib_handle_t* xlib_surface = NULL;
843 gate_gl_surface_t temp_surface = GATE_INIT_EMPTY;
844 NativeWindowType native_window;
845 EGLConfig egl_config;
846
847 do
848 {
849 egl_surface = (EGLSurface)surface->native_surface;
850 egl_context = (EGLContext)surface->native_context;
851 xlib_surface = (gate_xlib_handle_t*)surface->special_resources[0];
852 egl_display = (EGLDisplay)surface->special_resources[1];
853
854 switch (surface->surface_type)
855 {
856 case gate_gl_surface_type_external:
857 {
858 surface->width = width;
859 surface->height = height;
860 ret = GATE_RESULT_OK;
861 break;
862 }
863 case gate_gl_surface_type_image:
864 {
865 if ((surface->width != width) || (surface->height != height))
866 {
867 ret = gate_gl_surface_open(&temp_surface, gate_gl_surface_type_image, width, height, 0);
868 GATE_BREAK_IF_FAILED(ret);
869 gate_gl_surface_close(surface);
870 gate_mem_copy(surface, &temp_surface, sizeof(temp_surface));
871 }
872 break;
873 }
874 case gate_gl_surface_type_screen:
875 {
876 /*
877 egl.MakeCurrent(egl_display, NULL, NULL, EGL_NO_CONTEXT);
878
879 egl.DestroySurface(egl_display, egl_surface);
880 egl.DestroyContext(egl_display, egl_context);
881 egl.Terminate(egl_display);
882
883 ret = gate_gl_surface_egl_prepare(gate_egl_attribs_window, &egl_display, &egl_context, &egl_config);
884 GATE_BREAK_IF_FAILED(ret);
885
886 native_window = (NativeWindowType)gate_xlib_surface_get_handle(xlib_surface);
887
888 egl_surface = egl.CreateWindowSurface(egl_display, egl_config, native_window, NULL);
889 if(egl_surface == EGL_NO_SURFACE)
890 {
891 GATE_DEBUG_TRACE("eglCreateWindowSurface() failed");
892 ret = GATE_RESULT_OUTOFRESOURCES;
893 break;
894 }
895 */
896 gate_xlib_surface_get_client_size(xlib_surface, &width, &height);
897
898 /*
899 if(EGL_FALSE == egl.MakeCurrent(egl_display, egl_surface, egl_surface, egl_context))
900 {
901 GATE_DEBUG_TRACE("eglMakeCurrent() failed");
902 ret = GATE_RESULT_INVALIDSTATE;
903 break;
904 }
905 */
906 gate_gl_api.glViewport(0, 0, width, height);
907 surface->native_surface = egl_surface;
908 surface->native_context = egl_context;
909 surface->special_resources[0] = xlib_surface;
910 surface->special_resources[1] = egl_display;
911 surface->width = width;
912 surface->height = height;
913
914 ret = GATE_RESULT_OK;
915 break;
916 }
917 }
918
919 } while (0);
920
921 return ret;
922 }
923
924 gate_result_t gate_gl_surface_get_size(gate_gl_surface_t* surface, gate_uint32_t* width, gate_uint32_t* height)
925 {
926 if (width != NULL)
927 {
928 *width = surface->width;
929 }
930 if (height != NULL)
931 {
932 *height = surface->height;
933 }
934 return GATE_RESULT_OK;
935 }
936
937 gate_result_t gate_gl_surface_print_image(gate_gl_surface_t* surface, gate_rasterimage_t* target_image)
938 {
939 gate_result_t ret = GATE_RESULT_FAILED;
940 gate_size_t image_size = surface->width * surface->height * 4;
941 GLubyte* gl_image_bytes = NULL;
942 gate_rasterimage_t raster = GATE_INIT_EMPTY;
943 GLubyte const* ptr_src;
944 gate_color_t* ptr_dst;
945 gate_uint32_t y;
946 gate_uint32_t x;
947
948 do
949 {
950 gl_image_bytes = (GLubyte*)gate_mem_alloc(image_size);
951 if (NULL != gl_image_bytes)
952 {
953 ret = GATE_RESULT_OUTOFMEMORY;
954 break;
955 }
956 gate_mem_clear(gl_image_bytes, image_size);
957
958 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_DEFAULT, surface->width, surface->height, NULL))
959 {
960 ret = GATE_RESULT_OUTOFMEMORY;
961 break;
962 }
963
964 gate_gl_api.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
965 gate_gl_api.glReadPixels(0, 0, surface->width, surface->height, GL_RGBA, GL_UNSIGNED_BYTE, gl_image_bytes);
966
967 ptr_src = gl_image_bytes;
968 y = surface->height;
969 while (y != 0)
970 {
971 --y;
972 ptr_dst = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, y);
973 for (x = 0; x != surface->width; ++x)
974 {
975 ptr_dst->r = *(ptr_src++);
976 ptr_dst->g = *(ptr_src++);
977 ptr_dst->b = *(ptr_src++);
978 ptr_dst->a = 255;
979 ++ptr_src;
980 ++ptr_dst;
981 }
982 }
983
984 if (target_image)
985 {
986 gate_mem_copy(target_image, &raster, sizeof(raster));
987 gate_mem_clear(&raster, sizeof(raster));
988 }
989
990 ret = GATE_RESULT_OK;
991
992 } while (0);
993
994 gate_rasterimage_release(&raster);
995
996 if (NULL != gl_image_bytes)
997 {
998 gate_mem_dealloc(gl_image_bytes);
999 }
1000 return ret;
1001 }
1002 gate_result_t gate_gl_surface_run_event_loop(gate_gl_surface_t* surface, gate_gl_surface_events_t* event_callbacks, void* user_param)
1003 {
1004 gate_xlib_surface_handle_events(surface, event_callbacks, user_param);
1005 return GATE_RESULT_OK;
1006 }
1007 gate_result_t gate_gl_surface_exit_event_loop(gate_gl_surface_t* surface)
1008 {
1009 void* xlib_surface = surface->special_resources[0];
1010 gate_xlib_surface_cancel_events(xlib_surface);
1011 return GATE_RESULT_OK;
1012 }
1013
1014 gate_result_t gate_gl_surface_swap_buffers(gate_gl_surface_t* surface)
1015 {
1016 EGLSurface egl_surface = (EGLSurface)surface->native_surface;
1017 EGLDisplay egl_display = (EGLDisplay)surface->special_resources[1];
1018
1019 egl.SwapBuffers(egl_display, egl_surface);
1020 return true;
1021 }
1022
1023
1024
1025 #endif
1026