// ===================================================================================================================== // fennec, a free and open source game engine // Copyright © 2025 - 2026 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // ===================================================================================================================== #include #include #include #include namespace fennec { static const cstring& egl_translate_type(EGLint type) { static constexpr cstring opengl = "OpenGL"; static constexpr cstring gles = "GLES"; static constexpr cstring openvg = "OpenVG"; // this should never be used switch (type) { default: case EGL_OPENGL_API: return opengl; case EGL_OPENGL_ES_API: return gles; case EGL_OPENVG_API: return openvg; } } eglcontext::eglcontext(display_server* display) : glcontext(display) , _egldisplay(nullptr) , _eglcontext(nullptr) , _eglconfig(nullptr) , _eglvmajor(0) , _eglvminor(0) , _eglctype(0) { EGLint config_attrs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, // 4 EGL_NONE }; static constexpr size_t api_index = 4; EGLint context_attrs[] = { EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, EGL_NONE }; // Load EGL bindings assertf(gladLoaderLoadEGL(_egldisplay), "Unable to load EGL Bindings."); // Get the EGL display from the display server _egldisplay = eglGetDisplay(display->get_native_handle()); assertf(_egldisplay, "Failed to connect to egl display."); // Initialize EGL assertf(eglInitialize(_egldisplay, &_eglvmajor, &_eglvminor), "Failed to initialize egl."); logger::log(format("Initialized EGL v{}.{}", _eglvmajor, _eglvminor)); // Reload EGL bindings assertf(gladLoaderLoadEGL(_egldisplay), "Unable to load EGL Bindings."); // Attempt to bind to OpenGL or GLES if (not eglBindAPI(EGL_OPENGL_API)) { config_attrs[api_index] = EGL_OPENGL_ES_BIT; assertf(eglBindAPI(EGL_OPENGL_ES_API), "Failed to find suitable OpenGL API."); } // Select a configuration EGLint n; assertf(eglChooseConfig(_egldisplay, config_attrs, &_eglconfig, 1, &n), "Failed to find suitable OpenGL configuration."); // Create a context from the configuration and display _eglcontext = eglCreateContext(_egldisplay, _eglconfig, EGL_NO_CONTEXT, context_attrs); assertf(_eglcontext, "Failed to create OpenGL Context."); // Make the created context the current context to query some info eglMakeCurrent(_egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, _eglcontext); // Load OpenGL bindings assertf(gladLoaderLoadGL(), "Unable to load OpenGL Bindings."); // Query version information eglQueryContext(_egldisplay, _eglcontext, EGL_CONTEXT_CLIENT_TYPE, &_eglctype); glGetIntegerv(GL_MAJOR_VERSION, &_eglvmajor); glGetIntegerv(GL_MINOR_VERSION, &_eglvminor); // Set the version fields version.major = _eglvmajor; version.minor = _eglvminor; version.patch = 0; version.meta = _eglctype; logger::log(format("Created OpenGL Context: {} v{}.{}", egl_translate_type(version.meta), version.major, version.minor)); } eglcontext::~eglcontext() { // Ensure we are in the correct context eglMakeCurrent(_egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, _eglcontext); // Unload GL bindings gladLoaderUnloadGL(); // Cleanup the context eglMakeCurrent(_egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(_egldisplay, _eglcontext); eglTerminate(_egldisplay); eglReleaseThread(); // Unload EGL bindings gladLoaderUnloadEGL(); // Reset data members _egldisplay = nullptr; _eglconfig = nullptr; _eglcontext = nullptr; _eglvmajor = 0; _eglvminor = 0; // Reset version version.major = 0; version.minor = 0; version.patch = 0; version.meta = 0; } bool eglcontext::is_valid() { return _egldisplay != nullptr; } }