// ===================================================================================================================== // fennec, a free and open source game engine // Copyright © 2025 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 #include #include #include namespace fennec { static gfxcontext* _create_egl_context(display* display) { eglcontext* ctx = new eglcontext(display); if (not ctx->connected()) { delete ctx, ctx = nullptr; } return ctx; } STATIC_CONSTRUCTOR(_egl_init) { platform::add_driver(_create_egl_context, 1); } eglcontext::eglcontext(display* display) : gfxcontext(display, "EGL", this) , _egldisplay(nullptr), _eglcontext(nullptr) , _eglconfig(), _eglvmajor(0), _eglvminor(0) , _eglctype(0), _extensions(nullptr) { // Get the display format const display::pixel_format& fmt = _display->get_color_format(); // Currently empty EGLint context_attrs[] = { EGL_NONE }; // Configure the depth and rgb bit-depth EGLint config_attrs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_DEPTH_SIZE, fmt.depth, EGL_RED_SIZE, fmt.r, EGL_RED_SIZE, fmt.g, EGL_RED_SIZE, fmt.b, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, // 7 EGL_NONE }; // Attempt to retrieve an egl display from the native display _egldisplay = eglGetDisplay(_display->get_native_handle()); if (_egldisplay == nullptr) { cleanup(); return; } // Attempt to initialize egl if (not eglInitialize(_egldisplay, nullptr, nullptr)) { cleanup(); return; } // Attempt to bind to Core OpenGL, otherwise OpenGL ES if (not eglBindAPI(EGL_OPENGL_API)) { if (not eglBindAPI(EGL_OPENGL_ES_API)) { cleanup(); return; } config_attrs[7] = EGL_OPENGL_ES_BIT; // Change the support bit to OpenGL ES } // Select a configuration EGLint n; if (not eglChooseConfig(_egldisplay, config_attrs, &_eglconfig, 1, &n)) { cleanup(); return; } // Create the context _eglcontext = eglCreateContext(_egldisplay, _eglconfig, EGL_NO_CONTEXT, context_attrs); if (_eglcontext == nullptr) { cleanup(); return; } // make this the current context so we can retrieve the information below eglMakeCurrent(_egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, _eglcontext); // Query available extensions const char* ptr = eglQueryString(_egldisplay, EGL_EXTENSIONS); _extensions = { ptr, strlen(ptr) + 1 }; // Query the context and version eglQueryContext(_egldisplay, _eglcontext, EGL_CONTEXT_CLIENT_TYPE, &_eglctype); glGetIntegerv(GL_MAJOR_VERSION, &_eglvmajor); glGetIntegerv(GL_MINOR_VERSION, &_eglvminor); } eglcontext::~eglcontext() { cleanup(); } bool eglcontext::connected() { return _eglcontext != nullptr; } const cstring& eglcontext::get_name() { static constexpr cstring opengl = "OpenGL"; static constexpr cstring gles = "GLES"; static constexpr cstring openvg = "OpenVG"; // this should never be used switch (_eglctype) { default: case EGL_OPENGL_API: return opengl; case EGL_OPENGL_ES_API: return gles; case EGL_OPENVG_API: return openvg; } } bool eglcontext::check_extension(const cstring& ext) { return _extensions.find(ext) != _extensions.size(); } gfxsurface* eglcontext::create_surface(window* window) { return new eglsurface(this, window); } void eglcontext::make_current(gfxsurface* surface) { eglsurface* eglsurface = static_cast(surface); eglMakeCurrent(_egldisplay, eglsurface->get_egl_surface(), eglsurface->get_egl_surface(), _eglcontext); } void eglcontext::cleanup() { eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(_display, _eglcontext); eglTerminate(_display); eglReleaseThread(); _egldisplay = nullptr; _eglconfig = nullptr; _eglcontext = nullptr; _eglvmajor = 0; _eglvminor = 0; } }