GCC Code Coverage Report


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