// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "opengl_context_egl_wayland.h" #include "common/error.h" #include static const char* WAYLAND_EGL_MODNAME = "libwayland-egl.so.1"; OpenGLContextEGLWayland::OpenGLContextEGLWayland(const WindowInfo& wi) : OpenGLContextEGL(wi) { } OpenGLContextEGLWayland::~OpenGLContextEGLWayland() { if (m_wl_window) m_wl_egl_window_destroy(m_wl_window); if (m_wl_module) dlclose(m_wl_module); } std::unique_ptr OpenGLContextEGLWayland::Create(const WindowInfo& wi, std::span versions_to_try, Error* error) { std::unique_ptr context = std::make_unique(wi); if (!context->LoadModule(error) || !context->Initialize(versions_to_try, error)) return nullptr; return context; } std::unique_ptr OpenGLContextEGLWayland::CreateSharedContext(const WindowInfo& wi, Error* error) { std::unique_ptr context = std::make_unique(wi); context->m_display = m_display; if (!context->LoadModule(error) || !context->CreateContextAndSurface(m_version, m_context, false)) return nullptr; return context; } void OpenGLContextEGLWayland::ResizeSurface(u32 new_surface_width, u32 new_surface_height) { if (m_wl_window) m_wl_egl_window_resize(m_wl_window, new_surface_width, new_surface_height, 0, 0); OpenGLContextEGL::ResizeSurface(new_surface_width, new_surface_height); } EGLDisplay OpenGLContextEGLWayland::GetPlatformDisplay(Error* error) { EGLDisplay dpy = TryGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, "EGL_EXT_platform_wayland"); if (dpy == EGL_NO_DISPLAY) dpy = GetFallbackDisplay(error); return dpy; } EGLSurface OpenGLContextEGLWayland::CreatePlatformSurface(EGLConfig config, void* win, Error* error) { if (m_wl_window) { m_wl_egl_window_destroy(m_wl_window); m_wl_window = nullptr; } m_wl_window = m_wl_egl_window_create(static_cast(win), m_wi.surface_width, m_wi.surface_height); if (!m_wl_window) { Error::SetStringView(error, "wl_egl_window_create() failed"); return EGL_NO_SURFACE; } EGLSurface surface = TryCreatePlatformSurface(config, m_wl_window, error); if (surface == EGL_NO_SURFACE) { surface = CreateFallbackSurface(config, m_wl_window, error); if (surface == EGL_NO_SURFACE) { m_wl_egl_window_destroy(m_wl_window); m_wl_window = nullptr; } } return surface; } bool OpenGLContextEGLWayland::LoadModule(Error* error) { m_wl_module = dlopen(WAYLAND_EGL_MODNAME, RTLD_NOW | RTLD_GLOBAL); if (!m_wl_module) { const char* err = dlerror(); Error::SetStringFmt(error, "Loading {} failed: {}", WAYLAND_EGL_MODNAME, err ? err : ""); return false; } m_wl_egl_window_create = reinterpret_cast(dlsym(m_wl_module, "wl_egl_window_create")); m_wl_egl_window_destroy = reinterpret_cast(dlsym(m_wl_module, "wl_egl_window_destroy")); m_wl_egl_window_resize = reinterpret_cast(dlsym(m_wl_module, "wl_egl_window_resize")); if (!m_wl_egl_window_create || !m_wl_egl_window_destroy || !m_wl_egl_window_resize) { Error::SetStringFmt(error, "Failed to load one or more functions from {}.", WAYLAND_EGL_MODNAME); return false; } return true; }