GCC Code Coverage Report


Directory: src/gate/
File: src/gate/graphics/platform/opengl_xlib_impl.h
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 0 441 0.0%
Functions: 0 20 0.0%
Branches: 0 201 0.0%

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