From ddedd9b498cecb0a951e30868603ab7c3a46e2e7 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Thu, 6 Aug 2020 23:57:12 +0200 Subject: [PATCH 01/26] Add support for EGL/DRM on dolphin-nogui --- CMake/FindDRM.cmake | 41 + Source/Core/Common/CMakeLists.txt | 17 +- Source/Core/Common/GL/GLContext.cpp | 3 + Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 1483 ++++++++++++++++++ Source/Core/Common/GL/GLInterface/EGLDRM.h | 59 + Source/Core/Common/WindowSystemInfo.h | 1 + Source/Core/DolphinNoGUI/CMakeLists.txt | 1 + Source/Core/DolphinNoGUI/MainNoGUI.cpp | 5 +- Source/Core/DolphinNoGUI/Platform.h | 1 + Source/Core/DolphinNoGUI/PlatformDRM.cpp | 83 + 10 files changed, 1691 insertions(+), 3 deletions(-) create mode 100644 CMake/FindDRM.cmake create mode 100644 Source/Core/Common/GL/GLInterface/EGLDRM.cpp create mode 100644 Source/Core/Common/GL/GLInterface/EGLDRM.h create mode 100644 Source/Core/DolphinNoGUI/PlatformDRM.cpp diff --git a/CMake/FindDRM.cmake b/CMake/FindDRM.cmake new file mode 100644 index 000000000000..10d554f0fcdf --- /dev/null +++ b/CMake/FindDRM.cmake @@ -0,0 +1,41 @@ +# +# Try to find DRM library and include path. +# Once done this will define +# +# DRM_FOUND +# DRM_INCLUDE_PATH +# DRM_LIBRARY +# + +FIND_PATH(DRM_INCLUDE_PATH + NAMES + drm.h + PATHS + ${CMAKE_INCLUDE_PATH}/include/libdrm/ + ~/include/libdrm/ + /usr/include/libdrm/ + /usr/local/include/libdrm/ + /sw/include/libdrm/ + /opt/local/include/libdrm/ + DOC "The directory where drm.h resides") +FIND_LIBRARY(DRM_LIBRARY + NAMES DRM drm + PATHS + ${CMAKE_LIBRARY_PATH}/lib/ + ~/lib/ + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /sw/lib + /opt/local/lib + DOC "The DRM library") + +IF(DRM_INCLUDE_PATH) + INCLUDE_DIRECTORIES(${DRM_INCLUDE_PATH}) + SET(DRM_FOUND 1 CACHE STRING "Set to 1 if DRM is found, 0 otherwise") +ELSE(DRM_INCLUDE_PATH) + SET(DRM_FOUND 0 CACHE STRING "Set to 1 if DRM is found, 0 otherwise") +ENDIF(DRM_INCLUDE_PATH) + +MARK_AS_ADVANCED(DRM_FOUND) diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index a805635af60b..e4754f81400b 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -222,10 +222,18 @@ target_sources(common PRIVATE ) if(ENABLE_EGL AND EGL_FOUND) + find_package(DRM MODULE QUIET) + target_sources(common PRIVATE GL/GLInterface/EGL.cpp GL/GLInterface/EGL.h ) + if (DRM_FOUND) + target_sources(common PRIVATE + GL/GLInterface/EGLDRM.cpp + GL/GLInterface/EGLDRM.h + ) + endif() if(ANDROID) target_sources(common PRIVATE GL/GLInterface/EGLAndroid.cpp @@ -237,8 +245,13 @@ if(ENABLE_EGL AND EGL_FOUND) GL/GLInterface/EGLX11.h ) endif() - target_include_directories(common PRIVATE ${EGL_INCLUDE_DIRS}) - target_link_libraries(common PUBLIC ${EGL_LIBRARIES}) + if (DRM_FOUND) + target_include_directories(common PRIVATE ${EGL_INCLUDE_DIRS} ${DRM_INCLUDE_DIRS}) + target_link_libraries(common PUBLIC ${EGL_LIBRARIES} ${DRM_LIBRARY}) + else() + target_include_directories(common PRIVATE ${EGL_INCLUDE_DIRS}) + target_link_libraries(common PUBLIC ${EGL_LIBRARIES}) + endif() endif() if(WIN32) diff --git a/Source/Core/Common/GL/GLContext.cpp b/Source/Core/Common/GL/GLContext.cpp index d6969bcb55b0..f5adaab71ab6 100644 --- a/Source/Core/Common/GL/GLContext.cpp +++ b/Source/Core/Common/GL/GLContext.cpp @@ -17,6 +17,7 @@ #endif #if HAVE_EGL #include "Common/GL/GLInterface/EGL.h" +#include "Common/GL/GLInterface/EGLDRM.h" #if HAVE_X11 #include "Common/GL/GLInterface/EGLX11.h" #endif @@ -110,6 +111,8 @@ std::unique_ptr GLContext::Create(const WindowSystemInfo& wsi, bool s #if HAVE_EGL if (wsi.type == WindowSystemType::Headless || wsi.type == WindowSystemType::FBDev) context = std::make_unique(); + else if (wsi.type == WindowSystemType::DRM) + context = std::make_unique(); #endif if (!context) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp new file mode 100644 index 000000000000..3996178d0453 --- /dev/null +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -0,0 +1,1483 @@ +/* RetroArch - A frontend for libretro. + * Copyright (c) 2011-2017 - Daniel De Matteis + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +// Copyright 2012 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/GL/GLInterface/EGLDRM.h" + +#ifndef EGL_CONTEXT_FLAGS_KHR +#define EGL_CONTEXT_FLAGS_KHR 0x30FC +#endif + +#ifndef EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#endif + +#ifndef EGL_OPENGL_ES3_BIT_KHR +#define EGL_OPENGL_ES3_BIT_KHR 0x0040 +#endif + +#ifndef EGL_PLATFORM_GBM_KHR +#define EGL_PLATFORM_GBM_KHR 0x31D7 +#endif + +extern uint32_t g_connector_id; +extern int g_drm_fd; +extern uint32_t g_crtc_id; + +extern struct pollfd g_drm_fds; + +extern drmModeConnector *g_drm_connector; +extern drmModeModeInfo *g_drm_mode; +extern drmModeCrtc *g_orig_crtc; + +extern drmEventContext g_drm_evctx; + + +void egl_report_error(void); + +void egl_destroy(egl_ctx_data_t *egl); + +void egl_terminate(EGLDisplay dpy); + +void egl_swap_buffers(void *data); + +void egl_set_swap_interval(egl_ctx_data_t *egl, int interval); + +void egl_get_video_size(egl_ctx_data_t *egl, unsigned *width, unsigned *height); + +typedef bool (*egl_accept_config_cb_t)(void *display_data, EGLDisplay dpy, EGLConfig config); + +bool egl_initialize(EGLDisplay dpy, EGLint *major, EGLint *minor); + +bool egl_init_context_common( + egl_ctx_data_t *egl, EGLint *count, + const EGLint *attrib_ptr, + egl_accept_config_cb_t cb, + void *display_data); + +bool egl_init_context(egl_ctx_data_t *egl, + EGLenum platform, + void *display_data, + EGLint *major, + EGLint *minor, + EGLint *n, + const EGLint *attrib_ptr, + egl_accept_config_cb_t cb); + +bool egl_bind_api(EGLenum egl_api); + +bool egl_create_context(egl_ctx_data_t *egl, const EGLint *egl_attribs); + +bool egl_create_surface(egl_ctx_data_t *egl, void *native_window); + +bool egl_get_native_visual_id(egl_ctx_data_t *egl, EGLint *value); + +bool egl_get_config_attrib(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value); + +bool egl_has_config(egl_ctx_data_t *egl); + +#define _egl_query_surface(a, b, c, d) eglQuerySurface(a, b, c, d) +#define _egl_get_proc_address(a) eglGetProcAddress(a) +#define _egl_create_window_surface(a, b, c, d) eglCreateWindowSurface(a, b, c, d) +#define _egl_create_context(a, b, c, d) eglCreateContext(a, b, c, d) +#define _egl_get_configs(a, b, c, d) eglGetConfigs(a, b, c, d) +#define _egl_get_display(a) eglGetDisplay(a) +#define _egl_choose_config(a, b, c, d, e) eglChooseConfig(a, b, c, d, e) +#define _egl_make_current(a, b, c, d) eglMakeCurrent(a, b, c, d) +#define _egl_initialize(a, b, c) eglInitialize(a, b, c) +#define _egl_destroy_surface(a, b) eglDestroySurface(a, b) +#define _egl_destroy_context(a, b) eglDestroyContext(a, b) +#define _egl_get_current_context() eglGetCurrentContext() +#define _egl_get_error() eglGetError() +#define _egl_terminate(dpy) eglTerminate(dpy) +#define _egl_bind_api(a) eglBindAPI(a) +#define _egl_query_string(a, b) eglQueryString(a, b) +#define _egl_get_config_attrib(a, b, c, d) eglGetConfigAttrib(a, b, c, d) +#define _egl_swap_buffers(a, b) eglSwapBuffers(a, b) +#define _egl_swap_interval(a, b) eglSwapInterval(a, b) + +void egl_report_error(void) +{ + EGLint error = _egl_get_error(); + const char *str = NULL; + switch (error) + { + case EGL_SUCCESS: + str = "EGL_SUCCESS"; + break; + + case EGL_BAD_ACCESS: + str = "EGL_BAD_ACCESS"; + break; + + case EGL_BAD_ALLOC: + str = "EGL_BAD_ALLOC"; + break; + + case EGL_BAD_ATTRIBUTE: + str = "EGL_BAD_ATTRIBUTE"; + break; + + case EGL_BAD_CONFIG: + str = "EGL_BAD_CONFIG"; + break; + + case EGL_BAD_CONTEXT: + str = "EGL_BAD_CONTEXT"; + break; + + case EGL_BAD_CURRENT_SURFACE: + str = "EGL_BAD_CURRENT_SURFACE"; + break; + + case EGL_BAD_DISPLAY: + str = "EGL_BAD_DISPLAY"; + break; + + case EGL_BAD_MATCH: + str = "EGL_BAD_MATCH"; + break; + + case EGL_BAD_NATIVE_PIXMAP: + str = "EGL_BAD_NATIVE_PIXMAP"; + break; + + case EGL_BAD_NATIVE_WINDOW: + str = "EGL_BAD_NATIVE_WINDOW"; + break; + + case EGL_BAD_PARAMETER: + str = "EGL_BAD_PARAMETER"; + break; + + case EGL_BAD_SURFACE: + str = "EGL_BAD_SURFACE"; + break; + + default: + str = "Unknown"; + break; + } + + printf("[EGL]: #0x%x, %s\n", (unsigned)error, str); +} + +void egl_terminate(EGLDisplay dpy) +{ + _egl_terminate(dpy); +} + +bool egl_get_config_attrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, + EGLint *value) +{ + return _egl_get_config_attrib(dpy, config, attribute, value); +} + +bool egl_initialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + return _egl_initialize(dpy, major, minor); +} + +bool egl_bind_api(EGLenum egl_api) +{ + return _egl_bind_api(egl_api); +} + +void egl_destroy(egl_ctx_data_t *egl) +{ + if (egl->dpy) + { + _egl_make_current(egl->dpy, + EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (egl->ctx != EGL_NO_CONTEXT) + _egl_destroy_context(egl->dpy, egl->ctx); + + if (egl->surf != EGL_NO_SURFACE) + _egl_destroy_surface(egl->dpy, egl->surf); + egl_terminate(egl->dpy); + } + + /* Be as careful as possible in deinit. + * If we screw up, any TTY will not restore. + */ + + egl->ctx = EGL_NO_CONTEXT; + egl->surf = EGL_NO_SURFACE; + egl->dpy = EGL_NO_DISPLAY; + egl->config = 0; +} + +void egl_swap_buffers(void *data) +{ + egl_ctx_data_t *egl = (egl_ctx_data_t*)data; + if ( egl && + egl->dpy != EGL_NO_DISPLAY && + egl->surf != EGL_NO_SURFACE + ) + { + _egl_swap_buffers(egl->dpy, egl->surf); + } + else + printf("\nSWAP FAILED"); +} + +void egl_set_swap_interval(egl_ctx_data_t *egl, int interval) +{ + /* Can be called before initialization. + * Some contexts require that swap interval + * is known at startup time. + */ + egl->interval = interval; + + if (egl->dpy == EGL_NO_DISPLAY) + return; + if (!_egl_get_current_context()) + return; + + printf("[EGL]: eglSwapInterval(%u)\n", interval); + if (!_egl_swap_interval(egl->dpy, interval)) + { + printf("[EGL]: eglSwapInterval() failed.\n"); + egl_report_error(); + } +} + +void egl_get_video_size(egl_ctx_data_t *egl, unsigned *width, unsigned *height) +{ + *width = 0; + *height = 0; + + if (egl->dpy != EGL_NO_DISPLAY && egl->surf != EGL_NO_SURFACE) + { + EGLint gl_width, gl_height; + + _egl_query_surface(egl->dpy, egl->surf, EGL_WIDTH, &gl_width); + _egl_query_surface(egl->dpy, egl->surf, EGL_HEIGHT, &gl_height); + *width = gl_width; + *height = gl_height; + } +} + +bool check_egl_version(int minMajorVersion, int minMinorVersion) +{ + int count; + int major, minor; + const char *str = _egl_query_string(EGL_NO_DISPLAY, EGL_VERSION); + + if (!str) + return false; + + count = sscanf(str, "%d.%d", &major, &minor); + if (count != 2) + return false; + + if (major < minMajorVersion) + return false; + + if (major > minMajorVersion) + return true; + + if (minor >= minMinorVersion) + return true; + + return false; +} + +bool check_egl_client_extension(const char *name) +{ + size_t nameLen; + const char *str = _egl_query_string(EGL_NO_DISPLAY, EGL_EXTENSIONS); + + /* The EGL implementation doesn't support client extensions at all. */ + if (!str) + return false; + + nameLen = strlen(name); + while (*str != '\0') + { + /* Use strspn and strcspn to find the start position and length of each + * token in the extension string. Using strtok could also work, but + * that would require allocating a copy of the string. */ + size_t len = strcspn(str, " "); + if (len == nameLen && strncmp(str, name, nameLen) == 0) + return true; + str += len; + str += strspn(str, " "); + } + + return false; +} + +static EGLDisplay get_egl_display(EGLenum platform, void *native) +{ + if (platform != EGL_NONE) + { + /* If the client library supports at least EGL 1.5, then we can call + * eglGetPlatformDisplay. Otherwise, see if eglGetPlatformDisplayEXT + * is available. */ +#if defined(EGL_VERSION_1_5) + if (check_egl_version(1, 5)) + { + typedef EGLDisplay (EGLAPIENTRY * pfn_eglGetPlatformDisplay) + (EGLenum platform, void *native_display, const EGLAttrib *attrib_list); + pfn_eglGetPlatformDisplay ptr_eglGetPlatformDisplay; + + printf("[EGL] Found EGL client version >= 1.5, trying eglGetPlatformDisplay\n"); + ptr_eglGetPlatformDisplay = (pfn_eglGetPlatformDisplay) + _egl_get_proc_address("eglGetPlatformDisplay"); + + if (ptr_eglGetPlatformDisplay) + { + EGLDisplay dpy = ptr_eglGetPlatformDisplay(platform, native, NULL); + if (dpy != EGL_NO_DISPLAY) + return dpy; + } + } +#endif /* defined(EGL_VERSION_1_5) */ + +#if defined(EGL_EXT_platform_base) + if (check_egl_client_extension("EGL_EXT_platform_base")) + { + PFNEGLGETPLATFORMDISPLAYEXTPROC ptr_eglGetPlatformDisplayEXT; + + printf("[EGL] Found EGL_EXT_platform_base, trying eglGetPlatformDisplayEXT\n"); + ptr_eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) + _egl_get_proc_address("eglGetPlatformDisplayEXT"); + + if (ptr_eglGetPlatformDisplayEXT) + { + EGLDisplay dpy = ptr_eglGetPlatformDisplayEXT(platform, native, NULL); + if (dpy != EGL_NO_DISPLAY) + return dpy; + } + } +#endif /* defined(EGL_EXT_platform_base) */ + } + + /* Either the caller didn't provide a platform type, or the EGL + * implementation doesn't support eglGetPlatformDisplay. In this case, try + * eglGetDisplay and hope for the best. */ + printf("[EGL] Falling back to eglGetDisplay\n"); + return _egl_get_display((EGLNativeDisplayType) native); +} + +bool egl_get_native_visual_id(egl_ctx_data_t *egl, EGLint *value) +{ + if (!egl_get_config_attrib(egl->dpy, egl->config, + EGL_NATIVE_VISUAL_ID, value)) + { + printf("[EGL]: egl_get_native_visual_id failed.\n"); + return false; + } + + return true; +} + +bool egl_init_context_common( + egl_ctx_data_t *egl, EGLint *count, + const EGLint *attrib_ptr, + egl_accept_config_cb_t cb, + void *display_data) +{ + EGLint i; + EGLint matched = 0; + EGLConfig *configs = NULL; + if (!egl) + return false; + + if (!_egl_get_configs(egl->dpy, NULL, 0, count) || *count < 1) + { + printf("[EGL]: No configs to choose from.\n"); + return false; + } + + configs = (EGLConfig*)malloc(*count * sizeof(*configs)); + if (!configs) + return false; + + if (!_egl_choose_config(egl->dpy, attrib_ptr, + configs, *count, &matched) || !matched) + { + printf("[EGL]: No EGL configs with appropriate attributes.\n"); + return false; + } + + for (i = 0; i < *count; i++) + { + if (!cb || cb(display_data, egl->dpy, configs[i])) + { + egl->config = configs[i]; + break; + } + } + + free(configs); + + if (i == *count) + { + printf("[EGL]: No EGL config found which satifies requirements.\n"); + return false; + } + + return true; +} + + +bool egl_init_context(egl_ctx_data_t *egl, + EGLenum platform, + void *display_data, + EGLint *major, EGLint *minor, + EGLint *count, const EGLint *attrib_ptr, + egl_accept_config_cb_t cb) +{ + EGLDisplay dpy = get_egl_display(platform, display_data); + + if (dpy == EGL_NO_DISPLAY) + { + printf("[EGL]: Couldn't get EGL display.\n"); + return false; + } + + egl->dpy = dpy; + + if (!egl_initialize(egl->dpy, major, minor)) + return false; + + printf("[EGL]: EGL version: %d.%d\n", *major, *minor); + + return egl_init_context_common(egl, count, attrib_ptr, cb, + display_data); +} + +bool egl_create_context(egl_ctx_data_t *egl, const EGLint *egl_attribs) +{ + EGLContext ctx = _egl_create_context(egl->dpy, egl->config, EGL_NO_CONTEXT, + egl_attribs); + + if (ctx == EGL_NO_CONTEXT) + return false; + + egl->ctx = ctx; + + return true; +} + +bool egl_create_surface(egl_ctx_data_t *egl, void *native_window) +{ + EGLint window_attribs[] = { + EGL_RENDER_BUFFER, EGL_BACK_BUFFER, + EGL_NONE, + }; + + egl->surf = _egl_create_window_surface(egl->dpy, egl->config, (NativeWindowType)native_window, window_attribs); + + if (egl->surf == EGL_NO_SURFACE) + return false; + + /* Connect the context to the surface. */ + if (!_egl_make_current(egl->dpy, egl->surf, egl->surf, egl->ctx)) + return false; + + printf("[EGL]: Current context: %p.\n", (void*)_egl_get_current_context()); + + return true; +} + +bool egl_has_config(egl_ctx_data_t *egl) +{ + if (!egl->config) + { + printf("[EGL]: No EGL configurations available.\n"); + return false; + } + return true; +} + + + +bool drm_get_encoder(int fd); + +/* Restore the original CRTC. */ +void drm_restore_crtc(void); + +bool drm_get_resources(int fd); + +void drm_setup(int fd); + +void drm_free(void); + +bool drm_get_connector(int fd); + +float drm_get_refresh_rate(void *data); + +static bool drm_wait_flip(int timeout) +{ + g_drm_fds.revents = 0; + + if (poll(&g_drm_fds, 1, timeout) < 0) + return false; + + if (g_drm_fds.revents & (POLLHUP | POLLERR)) + return false; + + if (g_drm_fds.revents & POLLIN) + { + drmHandleEvent(g_drm_fd, &g_drm_evctx); + return true; + } + + return false; +} + +/* TODO/FIXME - globals */ +drmEventContext g_drm_evctx; +struct pollfd g_drm_fds; +uint32_t g_connector_id = 0; +int g_drm_fd = 0; +uint32_t g_crtc_id = 0; +drmModeCrtc *g_orig_crtc = NULL; +drmModeConnector *g_drm_connector = NULL; +drmModeModeInfo *g_drm_mode = NULL; + +/* TODO/FIXME - static globals */ +static drmModeRes *g_drm_resources = NULL; +static drmModeEncoder *g_drm_encoder = NULL; + +/* Restore the original CRTC. */ +void drm_restore_crtc(void) +{ + if (!g_orig_crtc) + return; + + drmModeSetCrtc(g_drm_fd, g_orig_crtc->crtc_id, + g_orig_crtc->buffer_id, + g_orig_crtc->x, + g_orig_crtc->y, + &g_connector_id, 1, &g_orig_crtc->mode); + + drmModeFreeCrtc(g_orig_crtc); + g_orig_crtc = NULL; +} + +bool drm_get_resources(int fd) +{ + g_drm_resources = drmModeGetResources(fd); + if (!g_drm_resources) + { + printf("[DRM]: Couldn't get device resources.\n"); + return false; + } + + return true; +} + +bool drm_get_connector(int fd) +{ + unsigned i; + unsigned monitor_index_count = 0; + unsigned monitor = 1; + + /* Enumerate all connectors. */ + + printf("[DRM]: Found %d connectors.\n", g_drm_resources->count_connectors); + + for (i = 0; (int)i < g_drm_resources->count_connectors; i++) + { + drmModeConnectorPtr conn = drmModeGetConnector( + fd, g_drm_resources->connectors[i]); + + if (conn) + { + bool connected = conn->connection == DRM_MODE_CONNECTED; + printf("[DRM]: Connector %d connected: %s\n", i, connected ? "yes" : "no"); + printf("[DRM]: Connector %d has %d modes.\n", i, conn->count_modes); + if (connected && conn->count_modes > 0) + { + monitor_index_count++; + printf("[DRM]: Connector %d assigned to monitor index: #%u.\n", i, monitor_index_count); + } + drmModeFreeConnector(conn); + } + } + + monitor_index_count = 0; + + for (i = 0; (int)i < g_drm_resources->count_connectors; i++) + { + g_drm_connector = drmModeGetConnector(fd, + g_drm_resources->connectors[i]); + + if (!g_drm_connector) + continue; + if (g_drm_connector->connection == DRM_MODE_CONNECTED + && g_drm_connector->count_modes > 0) + { + monitor_index_count++; + if (monitor_index_count == monitor) + { + printf("\n[DRM]: Matched monitor / connector\n"); + break; + } + } + + drmModeFreeConnector(g_drm_connector); + g_drm_connector = NULL; + } + + if (!g_drm_connector) + { + printf("[DRM]: Couldn't get device connector.\n"); + return false; + } + return true; +} + +bool drm_get_encoder(int fd) +{ + unsigned i; + + for (i = 0; (int)i < g_drm_resources->count_encoders; i++) + { + g_drm_encoder = drmModeGetEncoder(fd, g_drm_resources->encoders[i]); + + if (!g_drm_encoder) + continue; + + if (g_drm_encoder->encoder_id == g_drm_connector->encoder_id) + break; + + drmModeFreeEncoder(g_drm_encoder); + g_drm_encoder = NULL; + } + + if (!g_drm_encoder) + { + printf("[DRM]: Couldn't find DRM encoder.\n"); + return false; + } + + for (i = 0; (int)i < g_drm_connector->count_modes; i++) + { + printf("[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", + i, + g_drm_connector->modes[i].name, + g_drm_connector->modes[i].hdisplay, + g_drm_connector->modes[i].vdisplay, + g_drm_connector->modes[i].vrefresh); + } + + return true; +} + +void drm_setup(int fd) +{ + g_crtc_id = g_drm_encoder->crtc_id; + g_connector_id = g_drm_connector->connector_id; + g_orig_crtc = drmModeGetCrtc(fd, g_crtc_id); + if (!g_orig_crtc) + printf("[DRM]: Cannot find original CRTC.\n"); +} + +float drm_get_refresh_rate(void *data) +{ + float refresh_rate = 0.0f; + + if (g_drm_mode) + { + refresh_rate = g_drm_mode->clock * 1000.0f / g_drm_mode->htotal / g_drm_mode->vtotal; + } + + return refresh_rate; +} + +void drm_free(void) +{ + if (g_drm_encoder) + drmModeFreeEncoder(g_drm_encoder); + if (g_drm_connector) + drmModeFreeConnector(g_drm_connector); + if (g_drm_resources) + drmModeFreeResources(g_drm_resources); + + memset(&g_drm_fds, 0, sizeof(struct pollfd)); + memset(&g_drm_evctx, 0, sizeof(drmEventContext)); + + g_drm_encoder = NULL; + g_drm_connector = NULL; + g_drm_resources = NULL; +} + +typedef struct gfx_ctx_drm_data +{ + egl_ctx_data_t egl; + int fd; + int interval; + unsigned fb_width; + unsigned fb_height; + + bool core_hw_context_enable; + bool waiting_for_flip; + struct gbm_bo *bo; + struct gbm_bo *next_bo; + struct gbm_surface *gbm_surface; + struct gbm_device *gbm_dev; +} gfx_ctx_drm_data_t; + +static gfx_ctx_drm_data* g_drm; + +struct drm_fb +{ + struct gbm_bo *bo; + uint32_t fb_id; +}; + +static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data) +{ + struct drm_fb *fb = (struct drm_fb*)data; + + if (fb && fb->fb_id) + drmModeRmFB(g_drm_fd, fb->fb_id); + + free(fb); +} + +static struct drm_fb *drm_fb_get_from_bo(struct gbm_bo *bo) +{ + int ret; + unsigned width, height, stride, handle; + struct drm_fb *fb = (struct drm_fb*)calloc(1, sizeof(*fb)); + + fb->bo = bo; + + width = gbm_bo_get_width(bo); + height = gbm_bo_get_height(bo); + stride = gbm_bo_get_stride(bo); + handle = gbm_bo_get_handle(bo).u32; + + printf("[KMS]: New FB: %ux%u (stride: %u).\n", + width, height, stride); + + ret = drmModeAddFB(g_drm_fd, width, height, 24, 32, + stride, handle, &fb->fb_id); + if (ret < 0) + goto error; + + gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback); + return fb; + +error: + printf("[KMS]: Failed to create FB: %s\n", strerror(errno)); + free(fb); + return NULL; +} + +static void gfx_ctx_drm_swap_interval(void *data, int interval) +{ + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + drm->interval = interval; + + if (interval > 1) + printf("[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); +} + +static void drm_flip_handler(int fd, unsigned frame, + unsigned sec, unsigned usec, void *data) +{ +#if 0 + static unsigned first_page_flip; + static unsigned last_page_flip; + + if (!first_page_flip) + first_page_flip = frame; + + if (last_page_flip) + { + unsigned missed = frame - last_page_flip - 1; + if (missed) + printf("[KMS]: Missed %u VBlank(s) (Frame: %u, DRM frame: %u).\n", + missed, frame - first_page_flip, frame); + } + + last_page_flip = frame; +#endif + + *(bool*)data = false; +} + +static bool gfx_ctx_drm_wait_flip(gfx_ctx_drm_data_t *drm, bool block) +{ + int timeout = 0; + + if (!drm->waiting_for_flip) + return false; + + if (block) + timeout = -1; + + while (drm->waiting_for_flip) + { + if (!drm_wait_flip(timeout)) + break; + } + + if (drm->waiting_for_flip) + { printf("\nwait flip 2"); return true; } + + /* Page flip has taken place. */ + + /* This buffer is not on-screen anymore. Release it to GBM. */ + gbm_surface_release_buffer(drm->gbm_surface, drm->bo); + /* This buffer is being shown now. */ + drm->bo = drm->next_bo; + return false; +} + +static bool gfx_ctx_drm_queue_flip(gfx_ctx_drm_data_t *drm) +{ + struct drm_fb *fb = NULL; + + drm->next_bo = gbm_surface_lock_front_buffer(drm->gbm_surface); + fb = (struct drm_fb*)gbm_bo_get_user_data(drm->next_bo); + + if (!fb) + fb = (struct drm_fb*)drm_fb_get_from_bo(drm->next_bo); + + if (drmModePageFlip(g_drm_fd, g_crtc_id, fb->fb_id, + DRM_MODE_PAGE_FLIP_EVENT, &drm->waiting_for_flip) == 0) + return true; + + /* Failed to queue page flip. */ + printf("\nFailed to queue page flip\n"); + return false; +} + +static void gfx_ctx_drm_swap_buffers(void *data) +{ + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + unsigned max_swapchain_images = 2; //settings->uints.video_max_swapchain_images; + + egl_swap_buffers(&drm->egl); + + /* I guess we have to wait for flip to have taken + * place before another flip can be queued up. + * + * If true, we are still waiting for a flip + * (nonblocking mode, so just drop the frame). */ + if (gfx_ctx_drm_wait_flip(drm, drm->interval)) + { printf("\nwait flip"); return; } + + drm->waiting_for_flip = gfx_ctx_drm_queue_flip(drm); + + /* Triple-buffered page flips */ + if (max_swapchain_images >= 3 && + gbm_surface_has_free_buffers(drm->gbm_surface)) + return; + + gfx_ctx_drm_wait_flip(drm, true); +} + +static void gfx_ctx_drm_get_video_size(void *data, + unsigned *width, unsigned *height) +{ + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + + if (!drm) + { + printf("\nCannot get drm video size\n"); + return; + } + + *width = drm->fb_width; + *height = drm->fb_height; +} + +static void free_drm_resources(gfx_ctx_drm_data_t *drm) +{ + if (!drm) + return; + + /* Restore original CRTC. */ + drm_restore_crtc(); + + if (drm->gbm_surface) + gbm_surface_destroy(drm->gbm_surface); + + if (drm->gbm_dev) + gbm_device_destroy(drm->gbm_dev); + + drm_free(); + + if (drm->fd >= 0) + { + if (g_drm_fd >= 0) + { + drmDropMaster(g_drm_fd); + close(drm->fd); + } + } + + drm->gbm_surface = NULL; + drm->gbm_dev = NULL; + g_drm_fd = -1; +} + +static void gfx_ctx_drm_destroy_resources(gfx_ctx_drm_data_t *drm) +{ + if (!drm) + return; + + /* Make sure we acknowledge all page-flips. */ + gfx_ctx_drm_wait_flip(drm, true); + + egl_destroy(&drm->egl); + + free_drm_resources(drm); + + g_drm_mode = NULL; + g_crtc_id = 0; + g_connector_id = 0; + + drm->fb_width = 0; + drm->fb_height = 0; + + drm->bo = NULL; + drm->next_bo = NULL; +} + +static void *gfx_ctx_drm_init() +{ + int fd, i; + unsigned monitor_index; + unsigned gpu_index = 0; + const char *gpu = NULL; + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)calloc(1, sizeof(gfx_ctx_drm_data_t)); + + if (!drm) + return NULL; + drm->fd = -1; + + free_drm_resources(drm); + + drm->fd = open("/dev/dri/card0", O_RDWR); + if (drm->fd < 0) + { + printf("[KMS]: Couldn't open DRM device.\n"); + return nullptr; + } + + fd = drm->fd; + + if (!drm_get_resources(fd)) + { + printf("[KMS]: drm_get_resources failed\n"); + return nullptr; + } + + if (!drm_get_connector(fd)) + { + printf("[KMS]: drm_get_connector failed\n"); + return nullptr; + } + + if (!drm_get_encoder(fd)) + { + printf("[KMS]: drm_get_encoder failed\n"); + return nullptr; + } + + drm_setup(fd); + + /* Choose the optimal video mode for get_video_size(): + - the current video mode from the CRTC + - otherwise pick first connector mode */ + if (g_orig_crtc->mode_valid) + { + drm->fb_width = g_orig_crtc->mode.hdisplay; + drm->fb_height = g_orig_crtc->mode.vdisplay; + } + else + { + drm->fb_width = g_drm_connector->modes[0].hdisplay; + drm->fb_height = g_drm_connector->modes[0].vdisplay; + } + + drmSetMaster(g_drm_fd); + + drm->gbm_dev = gbm_create_device(fd); + + if (!drm->gbm_dev) + { + printf("[KMS]: Couldn't create GBM device.\n"); + return nullptr; + } + + /* Setup the flip handler. */ + g_drm_fds.fd = fd; + g_drm_fds.events = POLLIN; + g_drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; + g_drm_evctx.page_flip_handler = drm_flip_handler; + + g_drm_fd = fd; + + return drm; + +error: + gfx_ctx_drm_destroy_resources(drm); + + if (drm) + free(drm); + + return NULL; +} + +static EGLint *gfx_ctx_drm_egl_fill_attribs( + gfx_ctx_drm_data_t *drm, EGLint *attr) +{ + *attr++ = EGL_CONTEXT_CLIENT_VERSION; + *attr++ = drm->egl.major ? (EGLint)drm->egl.major : 2; +#ifdef EGL_KHR_create_context + if (drm->egl.minor > 0) + { + *attr++ = EGL_CONTEXT_MINOR_VERSION_KHR; + *attr++ = drm->egl.minor; + } +#endif + + *attr = EGL_NONE; + return attr; +} + +static bool gbm_choose_xrgb8888_cb(void *display_data, EGLDisplay dpy, EGLConfig config) +{ + EGLint r, g, b, id; + (void)display_data; + + /* Makes sure we have 8 bit color. */ + if (!egl_get_config_attrib(dpy, config, EGL_RED_SIZE, &r)) + return false; + if (!egl_get_config_attrib(dpy, config, EGL_GREEN_SIZE, &g)) + return false; + if (!egl_get_config_attrib(dpy, config, EGL_BLUE_SIZE, &b)) + return false; + + if (r != 8 || g != 8 || b != 8) + return false; + + if (!egl_get_config_attrib(dpy, config, EGL_NATIVE_VISUAL_ID, &id)) + return false; + + return id == GBM_FORMAT_XRGB8888; +} + +#define DRM_EGL_ATTRIBS_BASE \ + EGL_SURFACE_TYPE, 0/*EGL_WINDOW_BIT*/, \ + EGL_RED_SIZE, 8, \ + EGL_GREEN_SIZE, 8, \ + EGL_BLUE_SIZE, 8, \ + EGL_ALPHA_SIZE, 0, \ + EGL_DEPTH_SIZE, 0 + +#ifdef EGL_KHR_create_context + static const EGLint egl_attribs_gles3[] = { + DRM_EGL_ATTRIBS_BASE, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, + EGL_NONE, + }; +#endif + +static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t *drm) +{ + const EGLint *attrib_ptr = NULL; + EGLint major; + EGLint minor; + EGLint n; + EGLint egl_attribs[16]; + EGLint *egl_attribs_ptr = NULL; + EGLint *attr = NULL; + + attrib_ptr = egl_attribs_gles3; + + if (!egl_init_context(&drm->egl, EGL_PLATFORM_GBM_KHR, + (EGLNativeDisplayType)drm->gbm_dev, &major, + &minor, &n, attrib_ptr, gbm_choose_xrgb8888_cb)) + { + printf("\n[EGL] Cannot init context"); + goto error; + } + attr = gfx_ctx_drm_egl_fill_attribs(drm, egl_attribs); + egl_attribs_ptr = &egl_attribs[0]; + + if (!egl_create_context(&drm->egl, (attr != egl_attribs_ptr) + ? egl_attribs_ptr : NULL)) + { + printf("\n[EGL] Cannot create context"); + goto error; + } + + if (!egl_create_surface(&drm->egl, (EGLNativeWindowType)drm->gbm_surface)) + { + printf("\n[EGL] Cannot create context"); + return false; + } + + egl_swap_buffers(&drm->egl); + + return true; + +error: + egl_report_error(); + return false; +} + +static bool gfx_ctx_drm_set_video_mode(void *data, + unsigned width, unsigned height, + bool fullscreen) +{ + float refresh_mod; + int i, ret = 0; + struct drm_fb *fb = NULL; + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + bool black_frame_insertion = false; //settings->bools.video_black_frame_insertion; + float video_refresh_rate = 60; //settings->floats.video_refresh_rate; + + if (!drm) + return false; + + /* If we use black frame insertion, + * we fake a 60 Hz monitor for 120 Hz one, + * etc, so try to match that. */ + refresh_mod = black_frame_insertion + ? 0.5f : 1.0f; + + /* Find desired video mode, and use that. + * If not fullscreen, we get desired windowed size, + * which is not appropriate. */ + if ((width == 0 && height == 0) || !fullscreen) + g_drm_mode = &g_drm_connector->modes[0]; + else + { + /* Try to match refresh_rate as closely as possible. + * + * Lower resolutions tend to have multiple supported + * refresh rates as well. + */ + float minimum_fps_diff = 0.0f; + + /* Find best match. */ + for (i = 0; i < g_drm_connector->count_modes; i++) + { + float diff; + if (width != g_drm_connector->modes[i].hdisplay || + height != g_drm_connector->modes[i].vdisplay) + continue; + + diff = fabsf(refresh_mod * g_drm_connector->modes[i].vrefresh + - video_refresh_rate); + + if (!g_drm_mode || diff < minimum_fps_diff) + { + g_drm_mode = &g_drm_connector->modes[i]; + minimum_fps_diff = diff; + } + } + } + + if (!g_drm_mode) + { + printf("[KMS/EGL]: Did not find suitable video mode for %u x %u.\n", + width, height); + goto error; + } + + drm->fb_width = g_drm_mode->hdisplay; + drm->fb_height = g_drm_mode->vdisplay; + + /* Create GBM surface. */ + drm->gbm_surface = gbm_surface_create( + drm->gbm_dev, + drm->fb_width, + drm->fb_height, + GBM_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + + if (!drm->gbm_surface) + { + printf("[KMS/EGL]: Couldn't create GBM surface.\n"); + goto error; + } + + if (!gfx_ctx_drm_egl_set_video_mode(drm)) + { + printf("[KMS/EGL]: Couldn't set EGL video mode.\n"); + goto error; + } + + drm->bo = gbm_surface_lock_front_buffer(drm->gbm_surface); + + fb = (struct drm_fb*)gbm_bo_get_user_data(drm->bo); + + if (!fb) + fb = drm_fb_get_from_bo(drm->bo); + + ret = drmModeSetCrtc(g_drm_fd, + g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode); + if (ret < 0) + { + printf("[KMS/EGL]: drmModeSetCrtc failed\n"); + goto error; + } + return true; + +error: + gfx_ctx_drm_destroy_resources(drm); + + if (drm) + free(drm); + + return false; +} + +static void gfx_ctx_drm_destroy(void *data) +{ + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + + if (!drm) + return; + + gfx_ctx_drm_destroy_resources(drm); + free(drm); +} + +#ifndef EGL_KHR_create_context +#define EGL_KHR_create_context 1 +#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD +#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 +#endif /* EGL_KHR_create_context */ + +GLContextEGLDRM::~GLContextEGLDRM() +{ + DestroyWindowSurface(); + DestroyContext(); +} + +bool GLContextEGLDRM::IsHeadless() const +{ + return false; +} + +void GLContextEGLDRM::Swap() +{ + gfx_ctx_drm_swap_buffers(g_drm); +} +void GLContextEGLDRM::SwapInterval(int interval) +{ + gfx_ctx_drm_swap_interval(g_drm, interval); + egl_set_swap_interval(m_egl, interval); +} + +void* GLContextEGLDRM::GetFuncAddress(const std::string& name) +{ + return (void*)eglGetProcAddress(name.c_str()); +} + +// Create rendering window. +// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() +bool GLContextEGLDRM::Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) +{ + EGLint egl_major, egl_minor; + bool supports_core_profile = false; + + g_drm = (gfx_ctx_drm_data_t*)gfx_ctx_drm_init(); + egl_bind_api(EGL_OPENGL_ES_API); + gfx_ctx_drm_set_video_mode(g_drm, 1920, 1080, true); + m_backbuffer_width = 1920; + m_backbuffer_height = 1080; + + m_egl = &g_drm->egl; + m_opengl_mode = Mode::OpenGLES; + + m_supports_surfaceless = false; + const char* ext = eglQueryString(m_egl->dpy, EGL_EXTENSIONS); + if (strstr(ext, "EGL_KHR_surfaceless_context")) + { + printf("\nFound EGL_KHR_surfaceless_context\n"); + m_supports_surfaceless =true; + } + eglBindAPI(EGL_OPENGL_ES_API); + + return MakeCurrent(); +} + +std::unique_ptr GLContextEGLDRM::CreateSharedContext() +{ + printf("\nvoid GLContextEGLDRM::CreateSharedContext"); + std::unique_ptr new_context = std::make_unique(); + new_context->m_egl = (egl_ctx_data_t*)malloc(sizeof(egl_ctx_data_t)); + memcpy(new_context->m_egl, m_egl, sizeof(egl_ctx_data_t)); + + eglBindAPI(EGL_OPENGL_ES_API); + EGLint egl_attribs[16]; + EGLint *egl_attribs_ptr = NULL; + const EGLint *attrib_ptr = egl_attribs_gles3; + EGLint* attr = gfx_ctx_drm_egl_fill_attribs(g_drm, egl_attribs); + egl_attribs_ptr = &egl_attribs[0]; + new_context->m_egl->ctx = eglCreateContext(m_egl->dpy, m_egl->config, m_egl->ctx, egl_attribs_ptr); + if (!new_context->m_egl->ctx) + { + printf("\nError: eglCreateContext failed\n"); + egl_report_error(); + return nullptr; + } + eglBindAPI(EGL_OPENGL_ES_API); + new_context->m_opengl_mode = Mode::OpenGLES; + new_context->m_supports_surfaceless = m_supports_surfaceless; + new_context->m_is_shared = true; + if (!new_context->CreateWindowSurface()) + { + printf("\nError: CreateWindowSurface failed\n"); + egl_report_error(); + return nullptr; + } + return new_context; +} + +bool GLContextEGLDRM::CreateWindowSurface() +{ + EGLint attrib_list[] = { EGL_NONE, }; + printf("\nvoid GLContextEGLDRM::CreateWindowSurface"); + if (m_supports_surfaceless) + { + m_egl->surf = EGL_NO_SURFACE; + printf("\nCreated surfaceless context\n"); + return true; + } + + if (!IsHeadless()) + { + if (!egl_create_surface(m_egl, (EGLNativeWindowType)g_drm->gbm_surface)) + { + printf("\negl_create_surface failed, trying pbuffer\n"); + egl_report_error(); + goto pbuffer; + } + printf("\nm_egl_surface=0x%x",m_egl->surf); + // Get dimensions from the surface. + EGLint surface_width = 1, surface_height = 1; + if (!eglQuerySurface(m_egl->dpy, m_egl->surf, EGL_WIDTH, &surface_width) || + !eglQuerySurface(m_egl->dpy, m_egl->surf, EGL_HEIGHT, &surface_height)) + { + printf("Failed to get surface dimensions via eglQuerySurface. Size may be incorrect."); + } + m_backbuffer_width = static_cast(surface_width); + m_backbuffer_height = static_cast(surface_height); + return true; + } + +pbuffer: + m_egl->surf = eglCreatePbufferSurface(m_egl->dpy, m_egl->config, attrib_list); + if (!m_egl->surf) + { + printf("\nError: eglCreatePbufferSurface failed\n"); + egl_report_error(); + return false; + } + return true; +} + +void GLContextEGLDRM::DestroyWindowSurface() +{ + printf("\nvoid GLContextEGLDRM::DestroyWindowSurface"); + if (m_egl->surf == EGL_NO_SURFACE) + return; + + if (eglGetCurrentSurface(EGL_DRAW) == m_egl->surf) + eglMakeCurrent(m_egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!eglDestroySurface(m_egl->dpy, m_egl->surf)) + printf("\nCould not destroy window surface."); + m_egl->surf = EGL_NO_SURFACE; +} + +bool GLContextEGLDRM::MakeCurrent() +{ + printf("\nvoid GLContextEGLDRM::MakeCurrent()"); + return _egl_make_current(m_egl->dpy, g_drm->egl.surf, g_drm->egl.surf, m_egl->ctx); +} + +void GLContextEGLDRM::UpdateSurface(void* window_handle) +{ + printf("\nvoid GLContextEGLDRM::UpdateSurface(void* window_handle)"); + ClearCurrent(); + DestroyWindowSurface(); + CreateWindowSurface(); + MakeCurrent(); +} + +bool GLContextEGLDRM::ClearCurrent() +{ + printf("\nvoid GLContextEGLDRM::ClearCurrent()"); + return _egl_make_current(m_egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +} + +// Close backend +void GLContextEGLDRM::DestroyContext() +{ + printf("\nGLContextEGLDRM::DestroyContext()"); +if (!m_egl->ctx) + return; + + if (eglGetCurrentContext() == m_egl->ctx) + eglMakeCurrent(m_egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!eglDestroyContext(m_egl->dpy, m_egl->ctx)) + printf("\nCould not destroy drawing context."); + if (!m_is_shared && !eglTerminate(m_egl->dpy)) + printf("\nCould not destroy display connection."); + m_egl->ctx = EGL_NO_CONTEXT; + m_egl->dpy = EGL_NO_DISPLAY; +} diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.h b/Source/Core/Common/GL/GLInterface/EGLDRM.h new file mode 100644 index 000000000000..b8615cf7e67b --- /dev/null +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.h @@ -0,0 +1,59 @@ +// Copyright 2008 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include + +#include "Common/GL/GLContext.h" + +typedef struct +{ + EGLContext ctx; + EGLSurface surf; + EGLDisplay dpy; + EGLConfig config; + int interval; + + unsigned major; + unsigned minor; + +} egl_ctx_data_t; + +class GLContextEGLDRM : public GLContext +{ +public: + virtual ~GLContextEGLDRM() override; + + bool IsHeadless() const override; + + std::unique_ptr CreateSharedContext() override; + + bool MakeCurrent() override; + bool ClearCurrent() override; + + void UpdateSurface(void* window_handle) override; + + void Swap() override; + void SwapInterval(int interval) override; + + void* GetFuncAddress(const std::string& name) override; + +protected: + bool Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) override; + + bool CreateWindowSurface(); + void DestroyWindowSurface(); + void DestroyContext(); + + WindowSystemInfo m_wsi = {}; + + bool m_supports_surfaceless = false; + std::vector m_attribs; + + egl_ctx_data_t* m_egl; +}; diff --git a/Source/Core/Common/WindowSystemInfo.h b/Source/Core/Common/WindowSystemInfo.h index 244a985cdfeb..5bb9704a18da 100644 --- a/Source/Core/Common/WindowSystemInfo.h +++ b/Source/Core/Common/WindowSystemInfo.h @@ -13,6 +13,7 @@ enum class WindowSystemType X11, Wayland, FBDev, + DRM }; struct WindowSystemInfo diff --git a/Source/Core/DolphinNoGUI/CMakeLists.txt b/Source/Core/DolphinNoGUI/CMakeLists.txt index 3943582ad20e..d534eb9522fa 100644 --- a/Source/Core/DolphinNoGUI/CMakeLists.txt +++ b/Source/Core/DolphinNoGUI/CMakeLists.txt @@ -15,6 +15,7 @@ endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") target_sources(dolphin-nogui PRIVATE PlatformFBDev.cpp) + target_sources(dolphin-nogui PRIVATE PlatformDRM.cpp) endif() set_target_properties(dolphin-nogui PROPERTIES OUTPUT_NAME dolphin-emu-nogui) diff --git a/Source/Core/DolphinNoGUI/MainNoGUI.cpp b/Source/Core/DolphinNoGUI/MainNoGUI.cpp index 0bf4df23b87b..9faf1152de27 100644 --- a/Source/Core/DolphinNoGUI/MainNoGUI.cpp +++ b/Source/Core/DolphinNoGUI/MainNoGUI.cpp @@ -118,6 +118,8 @@ static std::unique_ptr GetPlatform(const optparse::Values& options) #ifdef __linux__ if (platform_name == "fbdev" || platform_name.empty()) return Platform::CreateFBDevPlatform(); + if (platform_name == "drm" || platform_name.empty()) + return Platform::CreateDRMPlatform(); #endif #ifdef _WIN32 @@ -141,7 +143,8 @@ int main(int argc, char* argv[]) "headless" #ifdef __linux__ , - "fbdev" + "fbdev", + "drm" #endif #if HAVE_X11 , diff --git a/Source/Core/DolphinNoGUI/Platform.h b/Source/Core/DolphinNoGUI/Platform.h index b0d98e58bef7..bc8c57a3cef9 100644 --- a/Source/Core/DolphinNoGUI/Platform.h +++ b/Source/Core/DolphinNoGUI/Platform.h @@ -38,6 +38,7 @@ class Platform #ifdef __linux__ static std::unique_ptr CreateFBDevPlatform(); + static std::unique_ptr CreateDRMPlatform(); #endif #ifdef _WIN32 diff --git a/Source/Core/DolphinNoGUI/PlatformDRM.cpp b/Source/Core/DolphinNoGUI/PlatformDRM.cpp new file mode 100644 index 000000000000..1784aaae4f84 --- /dev/null +++ b/Source/Core/DolphinNoGUI/PlatformDRM.cpp @@ -0,0 +1,83 @@ +// Copyright 2020 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include + +#include "DolphinNoGUI/Platform.h" + +#include "Common/MsgHandler.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" +#include "Core/State.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "VideoCommon/RenderBase.h" + +namespace +{ +class PlatformDRM : public Platform +{ +public: + ~PlatformDRM() override; + + bool Init() override; + void SetTitle(const std::string& string) override; + void MainLoop() override; + + WindowSystemInfo GetWindowSystemInfo() const override; + +private: +}; + +PlatformDRM::~PlatformDRM() +{ +} + +bool PlatformDRM::Init() +{ + return true; +} + +void PlatformDRM::SetTitle(const std::string& string) +{ + std::fprintf(stdout, "%s\n", string.c_str()); +} + +void PlatformDRM::MainLoop() +{ + while (IsRunning()) + { + UpdateRunningFlag(); + Core::HostDispatchJobs(); + + // TODO: Is this sleep appropriate? + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } +} + +WindowSystemInfo PlatformDRM::GetWindowSystemInfo() const +{ + WindowSystemInfo wsi; + wsi.type = WindowSystemType::DRM; + wsi.display_connection = nullptr; // EGL_DEFAULT_DISPLAY + wsi.render_window = nullptr; + wsi.render_surface = nullptr; + return wsi; +} +} // namespace + +std::unique_ptr Platform::CreateDRMPlatform() +{ + return std::make_unique(); +} From 0f2be8f1a2d9162ac3f02bfebc2a0674b149667b Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 00:27:27 +0200 Subject: [PATCH 02/26] Fix missing Cmake modules and code required to properly detect and link libdrm and libgbm --- CMake/FindDRM.cmake | 41 --------------------------- CMake/FindLibdrm.cmake | 45 ++++++++++++++++++++++++++++++ CMake/FindLibgbm.cmake | 46 +++++++++++++++++++++++++++++++ Source/Core/Common/CMakeLists.txt | 21 ++++++++------ 4 files changed, 103 insertions(+), 50 deletions(-) delete mode 100644 CMake/FindDRM.cmake create mode 100644 CMake/FindLibdrm.cmake create mode 100644 CMake/FindLibgbm.cmake diff --git a/CMake/FindDRM.cmake b/CMake/FindDRM.cmake deleted file mode 100644 index 10d554f0fcdf..000000000000 --- a/CMake/FindDRM.cmake +++ /dev/null @@ -1,41 +0,0 @@ -# -# Try to find DRM library and include path. -# Once done this will define -# -# DRM_FOUND -# DRM_INCLUDE_PATH -# DRM_LIBRARY -# - -FIND_PATH(DRM_INCLUDE_PATH - NAMES - drm.h - PATHS - ${CMAKE_INCLUDE_PATH}/include/libdrm/ - ~/include/libdrm/ - /usr/include/libdrm/ - /usr/local/include/libdrm/ - /sw/include/libdrm/ - /opt/local/include/libdrm/ - DOC "The directory where drm.h resides") -FIND_LIBRARY(DRM_LIBRARY - NAMES DRM drm - PATHS - ${CMAKE_LIBRARY_PATH}/lib/ - ~/lib/ - /usr/lib64 - /usr/lib - /usr/local/lib64 - /usr/local/lib - /sw/lib - /opt/local/lib - DOC "The DRM library") - -IF(DRM_INCLUDE_PATH) - INCLUDE_DIRECTORIES(${DRM_INCLUDE_PATH}) - SET(DRM_FOUND 1 CACHE STRING "Set to 1 if DRM is found, 0 otherwise") -ELSE(DRM_INCLUDE_PATH) - SET(DRM_FOUND 0 CACHE STRING "Set to 1 if DRM is found, 0 otherwise") -ENDIF(DRM_INCLUDE_PATH) - -MARK_AS_ADVANCED(DRM_FOUND) diff --git a/CMake/FindLibdrm.cmake b/CMake/FindLibdrm.cmake new file mode 100644 index 000000000000..4b39de31e9b4 --- /dev/null +++ b/CMake/FindLibdrm.cmake @@ -0,0 +1,45 @@ +#.rst: +# FindLibDRM +# ---------- +# Finds the LibDRM library +# +# This will define the following variables:: +# +# LIBDRM_FOUND - system has LibDRM +# LIBDRM_INCLUDE_DIRS - the LibDRM include directory +# LIBDRM_LIBRARIES - the LibDRM libraries +# +# and the following imported targets:: +# +# LibDRM::LibDRM - The LibDRM library + +if(PKG_CONFIG_FOUND) + pkg_check_modules(PC_LIBDRM libdrm>=2.4.82 QUIET) +endif() + +find_path(LIBDRM_INCLUDE_DIR NAMES drm.h + PATH_SUFFIXES libdrm drm + PATHS ${PC_LIBDRM_INCLUDEDIR}) +find_library(LIBDRM_LIBRARY NAMES drm + PATHS ${PC_LIBDRM_LIBDIR}) + +set(LIBDRM_VERSION ${PC_LIBDRM_VERSION}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibDRM + REQUIRED_VARS LIBDRM_LIBRARY LIBDRM_INCLUDE_DIR + VERSION_VAR LIBDRM_VERSION) + +if(LIBDRM_FOUND) + set(LIBDRM_LIBRARIES ${LIBDRM_LIBRARY}) + set(LIBDRM_INCLUDE_DIRS ${LIBDRM_INCLUDE_DIR}) + + if(NOT TARGET LIBDRM::LIBDRM) + add_library(LIBDRM::LIBDRM UNKNOWN IMPORTED) + set_target_properties(LIBDRM::LIBDRM PROPERTIES + IMPORTED_LOCATION "${LIBDRM_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${LIBDRM_INCLUDE_DIR}") + endif() +endif() + +mark_as_advanced(LIBDRM_INCLUDE_DIR LIBDRM_LIBRARY) diff --git a/CMake/FindLibgbm.cmake b/CMake/FindLibgbm.cmake new file mode 100644 index 000000000000..d2091cbfb426 --- /dev/null +++ b/CMake/FindLibgbm.cmake @@ -0,0 +1,46 @@ +# - Try to find gbm. +# Once done, this will define +# +# LIBGBM_INCLUDE_DIRS - the gbm include directories +# LIBGBM_LIBRARIES - link these to use gbm. +# +# Copyright (C) 2015 Igalia S.L. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +find_package(PkgConfig) +pkg_check_modules(PC_LIBGBM gbm) + +find_path(LIBGBM_INCLUDE_DIRS + NAMES gbm.h + HINTS ${PC_LIBGBM_INCLUDE_DIRS} ${PC_LIBGBM_INCUDEDIR} +) + +find_library(LIBGBM_LIBRARIES + NAMES gbm + HINTS ${PC_LIBGBM_LIBRARY_DIRS} ${PC_LIBGBM_LIBDIR} +) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBGBM DEFAULT_MSG LIBGBM_LIBRARIES) + +mark_as_advanced(LIBGBM_INCLUDE_DIRS LIBGBM_LIBRARIES) diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index e4754f81400b..6e220d9047bf 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -222,17 +222,20 @@ target_sources(common PRIVATE ) if(ENABLE_EGL AND EGL_FOUND) - find_package(DRM MODULE QUIET) - - target_sources(common PRIVATE + find_package(Libdrm) + find_package(Libgbm) + if (LIBDRM_FOUND AND LIBGBM_FOUND) + target_sources(common PRIVATE GL/GLInterface/EGL.cpp GL/GLInterface/EGL.h - ) - if (DRM_FOUND) - target_sources(common PRIVATE GL/GLInterface/EGLDRM.cpp GL/GLInterface/EGLDRM.h ) + else() + target_sources(common PRIVATE + GL/GLInterface/EGL.cpp + GL/GLInterface/EGL.h + ) endif() if(ANDROID) target_sources(common PRIVATE @@ -245,9 +248,9 @@ if(ENABLE_EGL AND EGL_FOUND) GL/GLInterface/EGLX11.h ) endif() - if (DRM_FOUND) - target_include_directories(common PRIVATE ${EGL_INCLUDE_DIRS} ${DRM_INCLUDE_DIRS}) - target_link_libraries(common PUBLIC ${EGL_LIBRARIES} ${DRM_LIBRARY}) + if (LIBDRM_FOUND AND LIBGBM_FOUND) + target_include_directories(common PRIVATE ${EGL_INCLUDE_DIRS} ${LIBDRM_INCLUDE_DIRS} ${LIBGBM_INCLUDE_DIRS}) + target_link_libraries(common PUBLIC ${EGL_LIBRARIES} ${LIBDRM_LIBRARIES} ${LIBGBM_LIBRARIES}) else() target_include_directories(common PRIVATE ${EGL_INCLUDE_DIRS}) target_link_libraries(common PUBLIC ${EGL_LIBRARIES}) From 1fa6fbc5387ecffcd18887a4894c3c3db84bd80a Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 10:35:28 +0200 Subject: [PATCH 03/26] Tidy up EGLDRM --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 430 +++++-------------- Source/Core/Common/GL/GLInterface/EGLDRM.h | 4 - 2 files changed, 107 insertions(+), 327 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index 3996178d0453..4b4ed1668e83 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -1,3 +1,9 @@ +// Copyright 2020 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +// EGL DRM GBM code based on RetroArch, RetroArch licenses follows + /* RetroArch - A frontend for libretro. * Copyright (c) 2011-2017 - Daniel De Matteis * @@ -13,10 +19,6 @@ * If not, see . */ -// Copyright 2012 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - #include #include #include @@ -58,182 +60,82 @@ #define EGL_PLATFORM_GBM_KHR 0x31D7 #endif -extern uint32_t g_connector_id; -extern int g_drm_fd; -extern uint32_t g_crtc_id; - -extern struct pollfd g_drm_fds; - -extern drmModeConnector *g_drm_connector; -extern drmModeModeInfo *g_drm_mode; -extern drmModeCrtc *g_orig_crtc; - -extern drmEventContext g_drm_evctx; - - -void egl_report_error(void); - -void egl_destroy(egl_ctx_data_t *egl); - -void egl_terminate(EGLDisplay dpy); - -void egl_swap_buffers(void *data); - -void egl_set_swap_interval(egl_ctx_data_t *egl, int interval); - -void egl_get_video_size(egl_ctx_data_t *egl, unsigned *width, unsigned *height); +#ifndef EGL_KHR_create_context +#define EGL_KHR_create_context 1 +#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD +#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 +#endif /* EGL_KHR_create_context */ typedef bool (*egl_accept_config_cb_t)(void *display_data, EGLDisplay dpy, EGLConfig config); -bool egl_initialize(EGLDisplay dpy, EGLint *major, EGLint *minor); - -bool egl_init_context_common( - egl_ctx_data_t *egl, EGLint *count, - const EGLint *attrib_ptr, - egl_accept_config_cb_t cb, - void *display_data); - -bool egl_init_context(egl_ctx_data_t *egl, - EGLenum platform, - void *display_data, - EGLint *major, - EGLint *minor, - EGLint *n, - const EGLint *attrib_ptr, - egl_accept_config_cb_t cb); - -bool egl_bind_api(EGLenum egl_api); - -bool egl_create_context(egl_ctx_data_t *egl, const EGLint *egl_attribs); - -bool egl_create_surface(egl_ctx_data_t *egl, void *native_window); - -bool egl_get_native_visual_id(egl_ctx_data_t *egl, EGLint *value); - -bool egl_get_config_attrib(EGLDisplay dpy, EGLConfig config, - EGLint attribute, EGLint *value); - -bool egl_has_config(egl_ctx_data_t *egl); - -#define _egl_query_surface(a, b, c, d) eglQuerySurface(a, b, c, d) -#define _egl_get_proc_address(a) eglGetProcAddress(a) -#define _egl_create_window_surface(a, b, c, d) eglCreateWindowSurface(a, b, c, d) -#define _egl_create_context(a, b, c, d) eglCreateContext(a, b, c, d) -#define _egl_get_configs(a, b, c, d) eglGetConfigs(a, b, c, d) -#define _egl_get_display(a) eglGetDisplay(a) -#define _egl_choose_config(a, b, c, d, e) eglChooseConfig(a, b, c, d, e) -#define _egl_make_current(a, b, c, d) eglMakeCurrent(a, b, c, d) -#define _egl_initialize(a, b, c) eglInitialize(a, b, c) -#define _egl_destroy_surface(a, b) eglDestroySurface(a, b) -#define _egl_destroy_context(a, b) eglDestroyContext(a, b) -#define _egl_get_current_context() eglGetCurrentContext() -#define _egl_get_error() eglGetError() -#define _egl_terminate(dpy) eglTerminate(dpy) -#define _egl_bind_api(a) eglBindAPI(a) -#define _egl_query_string(a, b) eglQueryString(a, b) -#define _egl_get_config_attrib(a, b, c, d) eglGetConfigAttrib(a, b, c, d) -#define _egl_swap_buffers(a, b) eglSwapBuffers(a, b) -#define _egl_swap_interval(a, b) eglSwapInterval(a, b) - -void egl_report_error(void) +typedef struct gfx_ctx_drm_data { - EGLint error = _egl_get_error(); - const char *str = NULL; - switch (error) - { - case EGL_SUCCESS: - str = "EGL_SUCCESS"; - break; - - case EGL_BAD_ACCESS: - str = "EGL_BAD_ACCESS"; - break; - - case EGL_BAD_ALLOC: - str = "EGL_BAD_ALLOC"; - break; - - case EGL_BAD_ATTRIBUTE: - str = "EGL_BAD_ATTRIBUTE"; - break; - - case EGL_BAD_CONFIG: - str = "EGL_BAD_CONFIG"; - break; - - case EGL_BAD_CONTEXT: - str = "EGL_BAD_CONTEXT"; - break; - - case EGL_BAD_CURRENT_SURFACE: - str = "EGL_BAD_CURRENT_SURFACE"; - break; - - case EGL_BAD_DISPLAY: - str = "EGL_BAD_DISPLAY"; - break; - - case EGL_BAD_MATCH: - str = "EGL_BAD_MATCH"; - break; - - case EGL_BAD_NATIVE_PIXMAP: - str = "EGL_BAD_NATIVE_PIXMAP"; - break; - - case EGL_BAD_NATIVE_WINDOW: - str = "EGL_BAD_NATIVE_WINDOW"; - break; - - case EGL_BAD_PARAMETER: - str = "EGL_BAD_PARAMETER"; - break; + egl_ctx_data_t egl; + int fd; + int interval; + unsigned fb_width; + unsigned fb_height; - case EGL_BAD_SURFACE: - str = "EGL_BAD_SURFACE"; - break; + bool core_hw_context_enable; + bool waiting_for_flip; + struct gbm_bo *bo; + struct gbm_bo *next_bo; + struct gbm_surface *gbm_surface; + struct gbm_device *gbm_dev; +} gfx_ctx_drm_data_t; - default: - str = "Unknown"; - break; - } +struct drm_fb +{ + struct gbm_bo *bo; + uint32_t fb_id; +}; - printf("[EGL]: #0x%x, %s\n", (unsigned)error, str); -} +/* TODO/FIXME - globals */ +static drmEventContext g_drm_evctx; +static struct pollfd g_drm_fds; +static uint32_t g_connector_id = 0; +static int g_drm_fd = 0; +static uint32_t g_crtc_id = 0; +static drmModeCrtc *g_orig_crtc = NULL; +static drmModeConnector *g_drm_connector = NULL; +static drmModeModeInfo *g_drm_mode = NULL; -void egl_terminate(EGLDisplay dpy) -{ - _egl_terminate(dpy); -} +/* TODO/FIXME - static globals */ +static drmModeRes *g_drm_resources = NULL; +static drmModeEncoder *g_drm_encoder = NULL; -bool egl_get_config_attrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, - EGLint *value) -{ - return _egl_get_config_attrib(dpy, config, attribute, value); -} +static gfx_ctx_drm_data* g_drm = NULL; -bool egl_initialize(EGLDisplay dpy, EGLint *major, EGLint *minor) -{ - return _egl_initialize(dpy, major, minor); -} +bool drm_get_encoder(int fd); -bool egl_bind_api(EGLenum egl_api) -{ - return _egl_bind_api(egl_api); -} +/* Restore the original CRTC. */ +void drm_restore_crtc(void); +bool drm_get_resources(int fd); +void drm_setup(int fd); +void drm_free(void); +bool drm_get_connector(int fd); +float drm_get_refresh_rate(void *data); -void egl_destroy(egl_ctx_data_t *egl) +static void egl_destroy(egl_ctx_data_t *egl) { if (egl->dpy) { - _egl_make_current(egl->dpy, + eglMakeCurrent(egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (egl->ctx != EGL_NO_CONTEXT) - _egl_destroy_context(egl->dpy, egl->ctx); + eglDestroyContext(egl->dpy, egl->ctx); if (egl->surf != EGL_NO_SURFACE) - _egl_destroy_surface(egl->dpy, egl->surf); - egl_terminate(egl->dpy); + eglDestroySurface(egl->dpy, egl->surf); + eglTerminate(egl->dpy); } /* Be as careful as possible in deinit. @@ -246,7 +148,7 @@ void egl_destroy(egl_ctx_data_t *egl) egl->config = 0; } -void egl_swap_buffers(void *data) +static void egl_swap_buffers(void *data) { egl_ctx_data_t *egl = (egl_ctx_data_t*)data; if ( egl && @@ -254,13 +156,11 @@ void egl_swap_buffers(void *data) egl->surf != EGL_NO_SURFACE ) { - _egl_swap_buffers(egl->dpy, egl->surf); + eglSwapBuffers(egl->dpy, egl->surf); } - else - printf("\nSWAP FAILED"); } -void egl_set_swap_interval(egl_ctx_data_t *egl, int interval) +static void egl_set_swap_interval(egl_ctx_data_t *egl, int interval) { /* Can be called before initialization. * Some contexts require that swap interval @@ -270,38 +170,21 @@ void egl_set_swap_interval(egl_ctx_data_t *egl, int interval) if (egl->dpy == EGL_NO_DISPLAY) return; - if (!_egl_get_current_context()) + if (!eglGetCurrentContext()) return; printf("[EGL]: eglSwapInterval(%u)\n", interval); - if (!_egl_swap_interval(egl->dpy, interval)) + if (!eglSwapInterval(egl->dpy, interval)) { - printf("[EGL]: eglSwapInterval() failed.\n"); - egl_report_error(); + printf("[EGL]: eglSwapInterval() failed 0x%x.\n", eglGetError()); } } -void egl_get_video_size(egl_ctx_data_t *egl, unsigned *width, unsigned *height) -{ - *width = 0; - *height = 0; - - if (egl->dpy != EGL_NO_DISPLAY && egl->surf != EGL_NO_SURFACE) - { - EGLint gl_width, gl_height; - - _egl_query_surface(egl->dpy, egl->surf, EGL_WIDTH, &gl_width); - _egl_query_surface(egl->dpy, egl->surf, EGL_HEIGHT, &gl_height); - *width = gl_width; - *height = gl_height; - } -} - -bool check_egl_version(int minMajorVersion, int minMinorVersion) +static bool check_egl_version(int minMajorVersion, int minMinorVersion) { int count; int major, minor; - const char *str = _egl_query_string(EGL_NO_DISPLAY, EGL_VERSION); + const char *str = eglQueryString(EGL_NO_DISPLAY, EGL_VERSION); if (!str) return false; @@ -322,10 +205,10 @@ bool check_egl_version(int minMajorVersion, int minMinorVersion) return false; } -bool check_egl_client_extension(const char *name) +static bool check_egl_client_extension(const char *name) { size_t nameLen; - const char *str = _egl_query_string(EGL_NO_DISPLAY, EGL_EXTENSIONS); + const char *str = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); /* The EGL implementation doesn't support client extensions at all. */ if (!str) @@ -363,7 +246,7 @@ static EGLDisplay get_egl_display(EGLenum platform, void *native) printf("[EGL] Found EGL client version >= 1.5, trying eglGetPlatformDisplay\n"); ptr_eglGetPlatformDisplay = (pfn_eglGetPlatformDisplay) - _egl_get_proc_address("eglGetPlatformDisplay"); + eglGetProcAddress("eglGetPlatformDisplay"); if (ptr_eglGetPlatformDisplay) { @@ -381,7 +264,7 @@ static EGLDisplay get_egl_display(EGLenum platform, void *native) printf("[EGL] Found EGL_EXT_platform_base, trying eglGetPlatformDisplayEXT\n"); ptr_eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) - _egl_get_proc_address("eglGetPlatformDisplayEXT"); + eglGetProcAddress("eglGetPlatformDisplayEXT"); if (ptr_eglGetPlatformDisplayEXT) { @@ -397,12 +280,12 @@ static EGLDisplay get_egl_display(EGLenum platform, void *native) * implementation doesn't support eglGetPlatformDisplay. In this case, try * eglGetDisplay and hope for the best. */ printf("[EGL] Falling back to eglGetDisplay\n"); - return _egl_get_display((EGLNativeDisplayType) native); + return eglGetDisplay((EGLNativeDisplayType) native); } -bool egl_get_native_visual_id(egl_ctx_data_t *egl, EGLint *value) +static bool egl_get_native_visual_id(egl_ctx_data_t *egl, EGLint *value) { - if (!egl_get_config_attrib(egl->dpy, egl->config, + if (!eglGetConfigAttrib(egl->dpy, egl->config, EGL_NATIVE_VISUAL_ID, value)) { printf("[EGL]: egl_get_native_visual_id failed.\n"); @@ -412,7 +295,7 @@ bool egl_get_native_visual_id(egl_ctx_data_t *egl, EGLint *value) return true; } -bool egl_init_context_common( +static bool egl_init_context_common( egl_ctx_data_t *egl, EGLint *count, const EGLint *attrib_ptr, egl_accept_config_cb_t cb, @@ -424,7 +307,7 @@ bool egl_init_context_common( if (!egl) return false; - if (!_egl_get_configs(egl->dpy, NULL, 0, count) || *count < 1) + if (!eglGetConfigs(egl->dpy, NULL, 0, count) || *count < 1) { printf("[EGL]: No configs to choose from.\n"); return false; @@ -434,7 +317,7 @@ bool egl_init_context_common( if (!configs) return false; - if (!_egl_choose_config(egl->dpy, attrib_ptr, + if (!eglChooseConfig(egl->dpy, attrib_ptr, configs, *count, &matched) || !matched) { printf("[EGL]: No EGL configs with appropriate attributes.\n"); @@ -462,7 +345,7 @@ bool egl_init_context_common( } -bool egl_init_context(egl_ctx_data_t *egl, +static bool egl_init_context(egl_ctx_data_t *egl, EGLenum platform, void *display_data, EGLint *major, EGLint *minor, @@ -479,7 +362,7 @@ bool egl_init_context(egl_ctx_data_t *egl, egl->dpy = dpy; - if (!egl_initialize(egl->dpy, major, minor)) + if (!eglInitialize(egl->dpy, major, minor)) return false; printf("[EGL]: EGL version: %d.%d\n", *major, *minor); @@ -488,9 +371,9 @@ bool egl_init_context(egl_ctx_data_t *egl, display_data); } -bool egl_create_context(egl_ctx_data_t *egl, const EGLint *egl_attribs) +static bool egl_create_context(egl_ctx_data_t *egl, const EGLint *egl_attribs) { - EGLContext ctx = _egl_create_context(egl->dpy, egl->config, EGL_NO_CONTEXT, + EGLContext ctx = eglCreateContext(egl->dpy, egl->config, EGL_NO_CONTEXT, egl_attribs); if (ctx == EGL_NO_CONTEXT) @@ -501,54 +384,27 @@ bool egl_create_context(egl_ctx_data_t *egl, const EGLint *egl_attribs) return true; } -bool egl_create_surface(egl_ctx_data_t *egl, void *native_window) +static bool egl_create_surface(egl_ctx_data_t *egl, void *native_window) { EGLint window_attribs[] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE, }; - egl->surf = _egl_create_window_surface(egl->dpy, egl->config, (NativeWindowType)native_window, window_attribs); + egl->surf = eglCreateWindowSurface(egl->dpy, egl->config, (NativeWindowType)native_window, window_attribs); if (egl->surf == EGL_NO_SURFACE) return false; /* Connect the context to the surface. */ - if (!_egl_make_current(egl->dpy, egl->surf, egl->surf, egl->ctx)) + if (!eglMakeCurrent(egl->dpy, egl->surf, egl->surf, egl->ctx)) return false; - printf("[EGL]: Current context: %p.\n", (void*)_egl_get_current_context()); + printf("[EGL]: Current context: %p.\n", (void*)eglGetCurrentContext()); return true; } -bool egl_has_config(egl_ctx_data_t *egl) -{ - if (!egl->config) - { - printf("[EGL]: No EGL configurations available.\n"); - return false; - } - return true; -} - - - -bool drm_get_encoder(int fd); - -/* Restore the original CRTC. */ -void drm_restore_crtc(void); - -bool drm_get_resources(int fd); - -void drm_setup(int fd); - -void drm_free(void); - -bool drm_get_connector(int fd); - -float drm_get_refresh_rate(void *data); - static bool drm_wait_flip(int timeout) { g_drm_fds.revents = 0; @@ -568,20 +424,6 @@ static bool drm_wait_flip(int timeout) return false; } -/* TODO/FIXME - globals */ -drmEventContext g_drm_evctx; -struct pollfd g_drm_fds; -uint32_t g_connector_id = 0; -int g_drm_fd = 0; -uint32_t g_crtc_id = 0; -drmModeCrtc *g_orig_crtc = NULL; -drmModeConnector *g_drm_connector = NULL; -drmModeModeInfo *g_drm_mode = NULL; - -/* TODO/FIXME - static globals */ -static drmModeRes *g_drm_resources = NULL; -static drmModeEncoder *g_drm_encoder = NULL; - /* Restore the original CRTC. */ void drm_restore_crtc(void) { @@ -653,10 +495,7 @@ bool drm_get_connector(int fd) { monitor_index_count++; if (monitor_index_count == monitor) - { - printf("\n[DRM]: Matched monitor / connector\n"); break; - } } drmModeFreeConnector(g_drm_connector); @@ -746,30 +585,6 @@ void drm_free(void) g_drm_resources = NULL; } -typedef struct gfx_ctx_drm_data -{ - egl_ctx_data_t egl; - int fd; - int interval; - unsigned fb_width; - unsigned fb_height; - - bool core_hw_context_enable; - bool waiting_for_flip; - struct gbm_bo *bo; - struct gbm_bo *next_bo; - struct gbm_surface *gbm_surface; - struct gbm_device *gbm_dev; -} gfx_ctx_drm_data_t; - -static gfx_ctx_drm_data* g_drm; - -struct drm_fb -{ - struct gbm_bo *bo; - uint32_t fb_id; -}; - static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data) { struct drm_fb *fb = (struct drm_fb*)data; @@ -1092,17 +907,17 @@ static bool gbm_choose_xrgb8888_cb(void *display_data, EGLDisplay dpy, EGLConfig (void)display_data; /* Makes sure we have 8 bit color. */ - if (!egl_get_config_attrib(dpy, config, EGL_RED_SIZE, &r)) + if (!eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r)) return false; - if (!egl_get_config_attrib(dpy, config, EGL_GREEN_SIZE, &g)) + if (!eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g)) return false; - if (!egl_get_config_attrib(dpy, config, EGL_BLUE_SIZE, &b)) + if (!eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b)) return false; if (r != 8 || g != 8 || b != 8) return false; - if (!egl_get_config_attrib(dpy, config, EGL_NATIVE_VISUAL_ID, &id)) + if (!eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &id)) return false; return id == GBM_FORMAT_XRGB8888; @@ -1140,7 +955,7 @@ static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t *drm) (EGLNativeDisplayType)drm->gbm_dev, &major, &minor, &n, attrib_ptr, gbm_choose_xrgb8888_cb)) { - printf("\n[EGL] Cannot init context"); + printf("\n[EGL] Cannot init context error 0x%x",eglGetError()); goto error; } attr = gfx_ctx_drm_egl_fill_attribs(drm, egl_attribs); @@ -1149,13 +964,13 @@ static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t *drm) if (!egl_create_context(&drm->egl, (attr != egl_attribs_ptr) ? egl_attribs_ptr : NULL)) { - printf("\n[EGL] Cannot create context"); + printf("\n[EGL] Cannot create context error 0x%x",eglGetError()); goto error; } if (!egl_create_surface(&drm->egl, (EGLNativeWindowType)drm->gbm_surface)) { - printf("\n[EGL] Cannot create context"); + printf("\n[EGL] Cannot create context error 0x%x",eglGetError()); return false; } @@ -1164,7 +979,6 @@ static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t *drm) return true; error: - egl_report_error(); return false; } @@ -1287,24 +1101,12 @@ static void gfx_ctx_drm_destroy(void *data) free(drm); } -#ifndef EGL_KHR_create_context -#define EGL_KHR_create_context 1 -#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 -#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB -#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD -#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD -#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE -#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF -#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 -#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 -#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 -#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 -#endif /* EGL_KHR_create_context */ GLContextEGLDRM::~GLContextEGLDRM() { DestroyWindowSurface(); DestroyContext(); + gfx_ctx_drm_destroy(g_drm); } bool GLContextEGLDRM::IsHeadless() const @@ -1331,25 +1133,18 @@ void* GLContextEGLDRM::GetFuncAddress(const std::string& name) // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() bool GLContextEGLDRM::Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) { - EGLint egl_major, egl_minor; - bool supports_core_profile = false; - g_drm = (gfx_ctx_drm_data_t*)gfx_ctx_drm_init(); - egl_bind_api(EGL_OPENGL_ES_API); + + eglBindAPI(EGL_OPENGL_ES_API); + gfx_ctx_drm_set_video_mode(g_drm, 1920, 1080, true); m_backbuffer_width = 1920; m_backbuffer_height = 1080; m_egl = &g_drm->egl; m_opengl_mode = Mode::OpenGLES; + m_supports_surfaceless = check_egl_client_extension("EGL_KHR_surfaceless_context"); - m_supports_surfaceless = false; - const char* ext = eglQueryString(m_egl->dpy, EGL_EXTENSIONS); - if (strstr(ext, "EGL_KHR_surfaceless_context")) - { - printf("\nFound EGL_KHR_surfaceless_context\n"); - m_supports_surfaceless =true; - } eglBindAPI(EGL_OPENGL_ES_API); return MakeCurrent(); @@ -1357,7 +1152,6 @@ bool GLContextEGLDRM::Initialize(const WindowSystemInfo& wsi, bool stereo, bool std::unique_ptr GLContextEGLDRM::CreateSharedContext() { - printf("\nvoid GLContextEGLDRM::CreateSharedContext"); std::unique_ptr new_context = std::make_unique(); new_context->m_egl = (egl_ctx_data_t*)malloc(sizeof(egl_ctx_data_t)); memcpy(new_context->m_egl, m_egl, sizeof(egl_ctx_data_t)); @@ -1371,8 +1165,7 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() new_context->m_egl->ctx = eglCreateContext(m_egl->dpy, m_egl->config, m_egl->ctx, egl_attribs_ptr); if (!new_context->m_egl->ctx) { - printf("\nError: eglCreateContext failed\n"); - egl_report_error(); + printf("\nError: eglCreateContext failed 0x%x\n", eglGetError()); return nullptr; } eglBindAPI(EGL_OPENGL_ES_API); @@ -1381,8 +1174,7 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() new_context->m_is_shared = true; if (!new_context->CreateWindowSurface()) { - printf("\nError: CreateWindowSurface failed\n"); - egl_report_error(); + printf("\nError: CreateWindowSurface failed 0x%x\n", eglGetError()); return nullptr; } return new_context; @@ -1391,7 +1183,6 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() bool GLContextEGLDRM::CreateWindowSurface() { EGLint attrib_list[] = { EGL_NONE, }; - printf("\nvoid GLContextEGLDRM::CreateWindowSurface"); if (m_supports_surfaceless) { m_egl->surf = EGL_NO_SURFACE; @@ -1403,8 +1194,7 @@ bool GLContextEGLDRM::CreateWindowSurface() { if (!egl_create_surface(m_egl, (EGLNativeWindowType)g_drm->gbm_surface)) { - printf("\negl_create_surface failed, trying pbuffer\n"); - egl_report_error(); + printf("\negl_create_surface failed, trying pbuffer failed 0x%x\n", eglGetError()); goto pbuffer; } printf("\nm_egl_surface=0x%x",m_egl->surf); @@ -1424,8 +1214,7 @@ bool GLContextEGLDRM::CreateWindowSurface() m_egl->surf = eglCreatePbufferSurface(m_egl->dpy, m_egl->config, attrib_list); if (!m_egl->surf) { - printf("\nError: eglCreatePbufferSurface failed\n"); - egl_report_error(); + printf("\nError: eglCreatePbufferSurface failed 0x%x\n", eglGetError()); return false; } return true; @@ -1433,7 +1222,6 @@ bool GLContextEGLDRM::CreateWindowSurface() void GLContextEGLDRM::DestroyWindowSurface() { - printf("\nvoid GLContextEGLDRM::DestroyWindowSurface"); if (m_egl->surf == EGL_NO_SURFACE) return; @@ -1446,13 +1234,11 @@ void GLContextEGLDRM::DestroyWindowSurface() bool GLContextEGLDRM::MakeCurrent() { - printf("\nvoid GLContextEGLDRM::MakeCurrent()"); - return _egl_make_current(m_egl->dpy, g_drm->egl.surf, g_drm->egl.surf, m_egl->ctx); + return eglMakeCurrent(m_egl->dpy, g_drm->egl.surf, g_drm->egl.surf, m_egl->ctx); } void GLContextEGLDRM::UpdateSurface(void* window_handle) { - printf("\nvoid GLContextEGLDRM::UpdateSurface(void* window_handle)"); ClearCurrent(); DestroyWindowSurface(); CreateWindowSurface(); @@ -1461,14 +1247,12 @@ void GLContextEGLDRM::UpdateSurface(void* window_handle) bool GLContextEGLDRM::ClearCurrent() { - printf("\nvoid GLContextEGLDRM::ClearCurrent()"); - return _egl_make_current(m_egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + return eglMakeCurrent(m_egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } // Close backend void GLContextEGLDRM::DestroyContext() { - printf("\nGLContextEGLDRM::DestroyContext()"); if (!m_egl->ctx) return; diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.h b/Source/Core/Common/GL/GLInterface/EGLDRM.h index b8615cf7e67b..b03dfea06227 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.h +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.h @@ -50,10 +50,6 @@ class GLContextEGLDRM : public GLContext void DestroyWindowSurface(); void DestroyContext(); - WindowSystemInfo m_wsi = {}; - bool m_supports_surfaceless = false; - std::vector m_attribs; - egl_ctx_data_t* m_egl; }; From bd3159621277b4ad13a030e55e071cead9bc186d Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 11:30:04 +0200 Subject: [PATCH 04/26] Use Dolphin logging system --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 134 +++++++++++-------- 1 file changed, 81 insertions(+), 53 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index 4b4ed1668e83..baebf998c4a0 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -43,6 +43,7 @@ #include #include "Common/GL/GLInterface/EGLDRM.h" +#include "Common/Logging/Log.h" #ifndef EGL_CONTEXT_FLAGS_KHR #define EGL_CONTEXT_FLAGS_KHR 0x30FC @@ -173,10 +174,10 @@ static void egl_set_swap_interval(egl_ctx_data_t *egl, int interval) if (!eglGetCurrentContext()) return; - printf("[EGL]: eglSwapInterval(%u)\n", interval); + INFO_LOG(VIDEO, "[EGL]: eglSwapInterval(%u)\n", interval); if (!eglSwapInterval(egl->dpy, interval)) { - printf("[EGL]: eglSwapInterval() failed 0x%x.\n", eglGetError()); + INFO_LOG(VIDEO, "[EGL]: eglSwapInterval() failed 0x%x.\n", eglGetError()); } } @@ -209,7 +210,6 @@ static bool check_egl_client_extension(const char *name) { size_t nameLen; const char *str = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); - /* The EGL implementation doesn't support client extensions at all. */ if (!str) return false; @@ -230,6 +230,34 @@ static bool check_egl_client_extension(const char *name) return false; } +static bool check_egl_display_extension(void* data, const char *name) +{ + size_t nameLen; + egl_ctx_data_t *egl = (egl_ctx_data_t*)data; + if (!egl || egl->dpy == EGL_NO_DISPLAY) + return false; + + const char *str = eglQueryString(egl->dpy, EGL_EXTENSIONS); + /* The EGL implementation doesn't support extensions at all. */ + if (!str) + return false; + + nameLen = strlen(name); + while (*str != '\0') + { + /* Use strspn and strcspn to find the start position and length of each + * token in the extension string. Using strtok could also work, but + * that would require allocating a copy of the string. */ + size_t len = strcspn(str, " "); + if (len == nameLen && strncmp(str, name, nameLen) == 0) + return true; + str += len; + str += strspn(str, " "); + } + + return false; +} + static EGLDisplay get_egl_display(EGLenum platform, void *native) { if (platform != EGL_NONE) @@ -244,7 +272,7 @@ static EGLDisplay get_egl_display(EGLenum platform, void *native) (EGLenum platform, void *native_display, const EGLAttrib *attrib_list); pfn_eglGetPlatformDisplay ptr_eglGetPlatformDisplay; - printf("[EGL] Found EGL client version >= 1.5, trying eglGetPlatformDisplay\n"); + INFO_LOG(VIDEO, "[EGL] Found EGL client version >= 1.5, trying eglGetPlatformDisplay\n"); ptr_eglGetPlatformDisplay = (pfn_eglGetPlatformDisplay) eglGetProcAddress("eglGetPlatformDisplay"); @@ -262,7 +290,7 @@ static EGLDisplay get_egl_display(EGLenum platform, void *native) { PFNEGLGETPLATFORMDISPLAYEXTPROC ptr_eglGetPlatformDisplayEXT; - printf("[EGL] Found EGL_EXT_platform_base, trying eglGetPlatformDisplayEXT\n"); + INFO_LOG(VIDEO, "[EGL] Found EGL_EXT_platform_base, trying eglGetPlatformDisplayEXT\n"); ptr_eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT"); @@ -279,7 +307,7 @@ static EGLDisplay get_egl_display(EGLenum platform, void *native) /* Either the caller didn't provide a platform type, or the EGL * implementation doesn't support eglGetPlatformDisplay. In this case, try * eglGetDisplay and hope for the best. */ - printf("[EGL] Falling back to eglGetDisplay\n"); + INFO_LOG(VIDEO, "[EGL] Falling back to eglGetDisplay\n"); return eglGetDisplay((EGLNativeDisplayType) native); } @@ -288,7 +316,7 @@ static bool egl_get_native_visual_id(egl_ctx_data_t *egl, EGLint *value) if (!eglGetConfigAttrib(egl->dpy, egl->config, EGL_NATIVE_VISUAL_ID, value)) { - printf("[EGL]: egl_get_native_visual_id failed.\n"); + INFO_LOG(VIDEO, "[EGL]: egl_get_native_visual_id failed.\n"); return false; } @@ -309,7 +337,7 @@ static bool egl_init_context_common( if (!eglGetConfigs(egl->dpy, NULL, 0, count) || *count < 1) { - printf("[EGL]: No configs to choose from.\n"); + INFO_LOG(VIDEO, "[EGL]: No configs to choose from.\n"); return false; } @@ -320,7 +348,7 @@ static bool egl_init_context_common( if (!eglChooseConfig(egl->dpy, attrib_ptr, configs, *count, &matched) || !matched) { - printf("[EGL]: No EGL configs with appropriate attributes.\n"); + INFO_LOG(VIDEO, "[EGL]: No EGL configs with appropriate attributes.\n"); return false; } @@ -337,7 +365,7 @@ static bool egl_init_context_common( if (i == *count) { - printf("[EGL]: No EGL config found which satifies requirements.\n"); + INFO_LOG(VIDEO, "[EGL]: No EGL config found which satifies requirements.\n"); return false; } @@ -356,7 +384,7 @@ static bool egl_init_context(egl_ctx_data_t *egl, if (dpy == EGL_NO_DISPLAY) { - printf("[EGL]: Couldn't get EGL display.\n"); + INFO_LOG(VIDEO, "[EGL]: Couldn't get EGL display.\n"); return false; } @@ -365,7 +393,7 @@ static bool egl_init_context(egl_ctx_data_t *egl, if (!eglInitialize(egl->dpy, major, minor)) return false; - printf("[EGL]: EGL version: %d.%d\n", *major, *minor); + INFO_LOG(VIDEO, "[EGL]: EGL version: %d.%d\n", *major, *minor); return egl_init_context_common(egl, count, attrib_ptr, cb, display_data); @@ -400,7 +428,7 @@ static bool egl_create_surface(egl_ctx_data_t *egl, void *native_window) if (!eglMakeCurrent(egl->dpy, egl->surf, egl->surf, egl->ctx)) return false; - printf("[EGL]: Current context: %p.\n", (void*)eglGetCurrentContext()); + INFO_LOG(VIDEO, "[EGL]: Current context: %p.\n", (void*)eglGetCurrentContext()); return true; } @@ -445,7 +473,7 @@ bool drm_get_resources(int fd) g_drm_resources = drmModeGetResources(fd); if (!g_drm_resources) { - printf("[DRM]: Couldn't get device resources.\n"); + INFO_LOG(VIDEO, "[DRM]: Couldn't get device resources.\n"); return false; } @@ -460,7 +488,7 @@ bool drm_get_connector(int fd) /* Enumerate all connectors. */ - printf("[DRM]: Found %d connectors.\n", g_drm_resources->count_connectors); + INFO_LOG(VIDEO, "[DRM]: Found %d connectors.\n", g_drm_resources->count_connectors); for (i = 0; (int)i < g_drm_resources->count_connectors; i++) { @@ -470,12 +498,12 @@ bool drm_get_connector(int fd) if (conn) { bool connected = conn->connection == DRM_MODE_CONNECTED; - printf("[DRM]: Connector %d connected: %s\n", i, connected ? "yes" : "no"); - printf("[DRM]: Connector %d has %d modes.\n", i, conn->count_modes); + INFO_LOG(VIDEO, "[DRM]: Connector %d connected: %s\n", i, connected ? "yes" : "no"); + INFO_LOG(VIDEO, "[DRM]: Connector %d has %d modes.\n", i, conn->count_modes); if (connected && conn->count_modes > 0) { monitor_index_count++; - printf("[DRM]: Connector %d assigned to monitor index: #%u.\n", i, monitor_index_count); + INFO_LOG(VIDEO, "[DRM]: Connector %d assigned to monitor index: #%u.\n", i, monitor_index_count); } drmModeFreeConnector(conn); } @@ -504,7 +532,7 @@ bool drm_get_connector(int fd) if (!g_drm_connector) { - printf("[DRM]: Couldn't get device connector.\n"); + INFO_LOG(VIDEO, "[DRM]: Couldn't get device connector.\n"); return false; } return true; @@ -530,13 +558,13 @@ bool drm_get_encoder(int fd) if (!g_drm_encoder) { - printf("[DRM]: Couldn't find DRM encoder.\n"); + INFO_LOG(VIDEO, "[DRM]: Couldn't find DRM encoder.\n"); return false; } for (i = 0; (int)i < g_drm_connector->count_modes; i++) { - printf("[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", + INFO_LOG(VIDEO, "[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", i, g_drm_connector->modes[i].name, g_drm_connector->modes[i].hdisplay, @@ -553,7 +581,7 @@ void drm_setup(int fd) g_connector_id = g_drm_connector->connector_id; g_orig_crtc = drmModeGetCrtc(fd, g_crtc_id); if (!g_orig_crtc) - printf("[DRM]: Cannot find original CRTC.\n"); + INFO_LOG(VIDEO, "[DRM]: Cannot find original CRTC.\n"); } float drm_get_refresh_rate(void *data) @@ -608,7 +636,7 @@ static struct drm_fb *drm_fb_get_from_bo(struct gbm_bo *bo) stride = gbm_bo_get_stride(bo); handle = gbm_bo_get_handle(bo).u32; - printf("[KMS]: New FB: %ux%u (stride: %u).\n", + INFO_LOG(VIDEO, "[KMS]: New FB: %ux%u (stride: %u).\n", width, height, stride); ret = drmModeAddFB(g_drm_fd, width, height, 24, 32, @@ -620,7 +648,7 @@ static struct drm_fb *drm_fb_get_from_bo(struct gbm_bo *bo) return fb; error: - printf("[KMS]: Failed to create FB: %s\n", strerror(errno)); + INFO_LOG(VIDEO, "[KMS]: Failed to create FB: %s\n", strerror(errno)); free(fb); return NULL; } @@ -631,7 +659,7 @@ static void gfx_ctx_drm_swap_interval(void *data, int interval) drm->interval = interval; if (interval > 1) - printf("[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); + INFO_LOG(VIDEO, "[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); } static void drm_flip_handler(int fd, unsigned frame, @@ -648,7 +676,7 @@ static void drm_flip_handler(int fd, unsigned frame, { unsigned missed = frame - last_page_flip - 1; if (missed) - printf("[KMS]: Missed %u VBlank(s) (Frame: %u, DRM frame: %u).\n", + INFO_LOG(VIDEO, "[KMS]: Missed %u VBlank(s) (Frame: %u, DRM frame: %u).\n", missed, frame - first_page_flip, frame); } @@ -675,7 +703,7 @@ static bool gfx_ctx_drm_wait_flip(gfx_ctx_drm_data_t *drm, bool block) } if (drm->waiting_for_flip) - { printf("\nwait flip 2"); return true; } + { INFO_LOG(VIDEO, "\nwait flip 2"); return true; } /* Page flip has taken place. */ @@ -701,7 +729,7 @@ static bool gfx_ctx_drm_queue_flip(gfx_ctx_drm_data_t *drm) return true; /* Failed to queue page flip. */ - printf("\nFailed to queue page flip\n"); + INFO_LOG(VIDEO, "\nFailed to queue page flip\n"); return false; } @@ -718,7 +746,7 @@ static void gfx_ctx_drm_swap_buffers(void *data) * If true, we are still waiting for a flip * (nonblocking mode, so just drop the frame). */ if (gfx_ctx_drm_wait_flip(drm, drm->interval)) - { printf("\nwait flip"); return; } + { INFO_LOG(VIDEO, "\nwait flip"); return; } drm->waiting_for_flip = gfx_ctx_drm_queue_flip(drm); @@ -737,7 +765,7 @@ static void gfx_ctx_drm_get_video_size(void *data, if (!drm) { - printf("\nCannot get drm video size\n"); + INFO_LOG(VIDEO, "\nCannot get drm video size\n"); return; } @@ -815,7 +843,7 @@ static void *gfx_ctx_drm_init() drm->fd = open("/dev/dri/card0", O_RDWR); if (drm->fd < 0) { - printf("[KMS]: Couldn't open DRM device.\n"); + INFO_LOG(VIDEO, "[KMS]: Couldn't open DRM device.\n"); return nullptr; } @@ -823,19 +851,19 @@ static void *gfx_ctx_drm_init() if (!drm_get_resources(fd)) { - printf("[KMS]: drm_get_resources failed\n"); + INFO_LOG(VIDEO, "[KMS]: drm_get_resources failed\n"); return nullptr; } if (!drm_get_connector(fd)) { - printf("[KMS]: drm_get_connector failed\n"); + INFO_LOG(VIDEO, "[KMS]: drm_get_connector failed\n"); return nullptr; } if (!drm_get_encoder(fd)) { - printf("[KMS]: drm_get_encoder failed\n"); + INFO_LOG(VIDEO, "[KMS]: drm_get_encoder failed\n"); return nullptr; } @@ -861,7 +889,7 @@ static void *gfx_ctx_drm_init() if (!drm->gbm_dev) { - printf("[KMS]: Couldn't create GBM device.\n"); + INFO_LOG(VIDEO, "[KMS]: Couldn't create GBM device.\n"); return nullptr; } @@ -955,7 +983,7 @@ static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t *drm) (EGLNativeDisplayType)drm->gbm_dev, &major, &minor, &n, attrib_ptr, gbm_choose_xrgb8888_cb)) { - printf("\n[EGL] Cannot init context error 0x%x",eglGetError()); + INFO_LOG(VIDEO, "\n[EGL] Cannot init context error 0x%x",eglGetError()); goto error; } attr = gfx_ctx_drm_egl_fill_attribs(drm, egl_attribs); @@ -964,13 +992,13 @@ static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t *drm) if (!egl_create_context(&drm->egl, (attr != egl_attribs_ptr) ? egl_attribs_ptr : NULL)) { - printf("\n[EGL] Cannot create context error 0x%x",eglGetError()); + INFO_LOG(VIDEO, "\n[EGL] Cannot create context error 0x%x",eglGetError()); goto error; } if (!egl_create_surface(&drm->egl, (EGLNativeWindowType)drm->gbm_surface)) { - printf("\n[EGL] Cannot create context error 0x%x",eglGetError()); + INFO_LOG(VIDEO, "\n[EGL] Cannot create context error 0x%x",eglGetError()); return false; } @@ -1037,7 +1065,7 @@ static bool gfx_ctx_drm_set_video_mode(void *data, if (!g_drm_mode) { - printf("[KMS/EGL]: Did not find suitable video mode for %u x %u.\n", + INFO_LOG(VIDEO, "[KMS/EGL]: Did not find suitable video mode for %u x %u.\n", width, height); goto error; } @@ -1055,13 +1083,13 @@ static bool gfx_ctx_drm_set_video_mode(void *data, if (!drm->gbm_surface) { - printf("[KMS/EGL]: Couldn't create GBM surface.\n"); + INFO_LOG(VIDEO, "[KMS/EGL]: Couldn't create GBM surface.\n"); goto error; } if (!gfx_ctx_drm_egl_set_video_mode(drm)) { - printf("[KMS/EGL]: Couldn't set EGL video mode.\n"); + INFO_LOG(VIDEO, "[KMS/EGL]: Couldn't set EGL video mode.\n"); goto error; } @@ -1076,7 +1104,7 @@ static bool gfx_ctx_drm_set_video_mode(void *data, g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode); if (ret < 0) { - printf("[KMS/EGL]: drmModeSetCrtc failed\n"); + INFO_LOG(VIDEO, "[KMS/EGL]: drmModeSetCrtc failed\n"); goto error; } return true; @@ -1143,7 +1171,7 @@ bool GLContextEGLDRM::Initialize(const WindowSystemInfo& wsi, bool stereo, bool m_egl = &g_drm->egl; m_opengl_mode = Mode::OpenGLES; - m_supports_surfaceless = check_egl_client_extension("EGL_KHR_surfaceless_context"); + m_supports_surfaceless = check_egl_display_extension(m_egl,"EGL_KHR_surfaceless_context"); eglBindAPI(EGL_OPENGL_ES_API); @@ -1165,7 +1193,7 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() new_context->m_egl->ctx = eglCreateContext(m_egl->dpy, m_egl->config, m_egl->ctx, egl_attribs_ptr); if (!new_context->m_egl->ctx) { - printf("\nError: eglCreateContext failed 0x%x\n", eglGetError()); + INFO_LOG(VIDEO, "\nError: eglCreateContext failed 0x%x\n", eglGetError()); return nullptr; } eglBindAPI(EGL_OPENGL_ES_API); @@ -1174,7 +1202,7 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() new_context->m_is_shared = true; if (!new_context->CreateWindowSurface()) { - printf("\nError: CreateWindowSurface failed 0x%x\n", eglGetError()); + INFO_LOG(VIDEO, "\nError: CreateWindowSurface failed 0x%x\n", eglGetError()); return nullptr; } return new_context; @@ -1186,7 +1214,7 @@ bool GLContextEGLDRM::CreateWindowSurface() if (m_supports_surfaceless) { m_egl->surf = EGL_NO_SURFACE; - printf("\nCreated surfaceless context\n"); + INFO_LOG(VIDEO, "\nCreated surfaceless context\n"); return true; } @@ -1194,16 +1222,16 @@ bool GLContextEGLDRM::CreateWindowSurface() { if (!egl_create_surface(m_egl, (EGLNativeWindowType)g_drm->gbm_surface)) { - printf("\negl_create_surface failed, trying pbuffer failed 0x%x\n", eglGetError()); + INFO_LOG(VIDEO, "\negl_create_surface failed, trying pbuffer failed 0x%x\n", eglGetError()); goto pbuffer; } - printf("\nm_egl_surface=0x%x",m_egl->surf); + INFO_LOG(VIDEO, "\nm_egl_surface=0x%x",m_egl->surf); // Get dimensions from the surface. EGLint surface_width = 1, surface_height = 1; if (!eglQuerySurface(m_egl->dpy, m_egl->surf, EGL_WIDTH, &surface_width) || !eglQuerySurface(m_egl->dpy, m_egl->surf, EGL_HEIGHT, &surface_height)) { - printf("Failed to get surface dimensions via eglQuerySurface. Size may be incorrect."); + INFO_LOG(VIDEO, "Failed to get surface dimensions via eglQuerySurface. Size may be incorrect."); } m_backbuffer_width = static_cast(surface_width); m_backbuffer_height = static_cast(surface_height); @@ -1214,7 +1242,7 @@ bool GLContextEGLDRM::CreateWindowSurface() m_egl->surf = eglCreatePbufferSurface(m_egl->dpy, m_egl->config, attrib_list); if (!m_egl->surf) { - printf("\nError: eglCreatePbufferSurface failed 0x%x\n", eglGetError()); + INFO_LOG(VIDEO, "\nError: eglCreatePbufferSurface failed 0x%x\n", eglGetError()); return false; } return true; @@ -1228,7 +1256,7 @@ void GLContextEGLDRM::DestroyWindowSurface() if (eglGetCurrentSurface(EGL_DRAW) == m_egl->surf) eglMakeCurrent(m_egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (!eglDestroySurface(m_egl->dpy, m_egl->surf)) - printf("\nCould not destroy window surface."); + INFO_LOG(VIDEO, "\nCould not destroy window surface."); m_egl->surf = EGL_NO_SURFACE; } @@ -1259,9 +1287,9 @@ if (!m_egl->ctx) if (eglGetCurrentContext() == m_egl->ctx) eglMakeCurrent(m_egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (!eglDestroyContext(m_egl->dpy, m_egl->ctx)) - printf("\nCould not destroy drawing context."); + INFO_LOG(VIDEO, "\nCould not destroy drawing context."); if (!m_is_shared && !eglTerminate(m_egl->dpy)) - printf("\nCould not destroy display connection."); + INFO_LOG(VIDEO, "\nCould not destroy display connection."); m_egl->ctx = EGL_NO_CONTEXT; m_egl->dpy = EGL_NO_DISPLAY; } From 0a05a524bd770d51359fa40e416d2b16a52057d1 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 13:11:03 +0200 Subject: [PATCH 05/26] Remove hardcoded video mode, try to match native game rate --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 26 +++++++------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index baebf998c4a0..e617592e677d 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -44,6 +44,7 @@ #include "Common/GL/GLInterface/EGLDRM.h" #include "Common/Logging/Log.h" +#include "Core/HW/VideoInterface.h" //for TargetRefreshRate #ifndef EGL_CONTEXT_FLAGS_KHR #define EGL_CONTEXT_FLAGS_KHR 0x30FC @@ -1014,22 +1015,14 @@ static bool gfx_ctx_drm_set_video_mode(void *data, unsigned width, unsigned height, bool fullscreen) { - float refresh_mod; int i, ret = 0; struct drm_fb *fb = NULL; gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; - bool black_frame_insertion = false; //settings->bools.video_black_frame_insertion; - float video_refresh_rate = 60; //settings->floats.video_refresh_rate; + float video_refresh_rate = (float)VideoInterface::GetTargetRefreshRate(); if (!drm) return false; - /* If we use black frame insertion, - * we fake a 60 Hz monitor for 120 Hz one, - * etc, so try to match that. */ - refresh_mod = black_frame_insertion - ? 0.5f : 1.0f; - /* Find desired video mode, and use that. * If not fullscreen, we get desired windowed size, * which is not appropriate. */ @@ -1052,8 +1045,7 @@ static bool gfx_ctx_drm_set_video_mode(void *data, height != g_drm_connector->modes[i].vdisplay) continue; - diff = fabsf(refresh_mod * g_drm_connector->modes[i].vrefresh - - video_refresh_rate); + diff = fabsf(g_drm_connector->modes[i].vrefresh - video_refresh_rate); if (!g_drm_mode || diff < minimum_fps_diff) { @@ -1165,9 +1157,10 @@ bool GLContextEGLDRM::Initialize(const WindowSystemInfo& wsi, bool stereo, bool eglBindAPI(EGL_OPENGL_ES_API); - gfx_ctx_drm_set_video_mode(g_drm, 1920, 1080, true); - m_backbuffer_width = 1920; - m_backbuffer_height = 1080; + // Use current video mode, do not switch + gfx_ctx_drm_set_video_mode(g_drm, 0, 0, false); + m_backbuffer_width = g_drm->fb_width; + m_backbuffer_height = g_drm->fb_height; m_egl = &g_drm->egl; m_opengl_mode = Mode::OpenGLES; @@ -1193,7 +1186,7 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() new_context->m_egl->ctx = eglCreateContext(m_egl->dpy, m_egl->config, m_egl->ctx, egl_attribs_ptr); if (!new_context->m_egl->ctx) { - INFO_LOG(VIDEO, "\nError: eglCreateContext failed 0x%x\n", eglGetError()); + ERROR_LOG(VIDEO, "\nError: eglCreateContext failed 0x%x\n", eglGetError()); return nullptr; } eglBindAPI(EGL_OPENGL_ES_API); @@ -1202,7 +1195,7 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() new_context->m_is_shared = true; if (!new_context->CreateWindowSurface()) { - INFO_LOG(VIDEO, "\nError: CreateWindowSurface failed 0x%x\n", eglGetError()); + ERROR_LOG(VIDEO, "\nError: CreateWindowSurface failed 0x%x\n", eglGetError()); return nullptr; } return new_context; @@ -1225,7 +1218,6 @@ bool GLContextEGLDRM::CreateWindowSurface() INFO_LOG(VIDEO, "\negl_create_surface failed, trying pbuffer failed 0x%x\n", eglGetError()); goto pbuffer; } - INFO_LOG(VIDEO, "\nm_egl_surface=0x%x",m_egl->surf); // Get dimensions from the surface. EGLint surface_width = 1, surface_height = 1; if (!eglQuerySurface(m_egl->dpy, m_egl->surf, EGL_WIDTH, &surface_width) || From 56b39ef782efdeaf6aac2dd4926ca042ba189e8d Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 14:25:28 +0200 Subject: [PATCH 06/26] Fix lint checks --- Source/Core/Common/GL/GLInterface/EGLDRM.h | 16 ++++++++-------- Source/Core/DolphinNoGUI/MainNoGUI.cpp | 3 +-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.h b/Source/Core/Common/GL/GLInterface/EGLDRM.h index b03dfea06227..61bb6a7cfe23 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.h +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.h @@ -13,14 +13,14 @@ typedef struct { - EGLContext ctx; - EGLSurface surf; - EGLDisplay dpy; - EGLConfig config; - int interval; - - unsigned major; - unsigned minor; + EGLContext ctx; + EGLSurface surf; + EGLDisplay dpy; + EGLConfig config; + int interval; + + unsigned major; + unsigned minor; } egl_ctx_data_t; diff --git a/Source/Core/DolphinNoGUI/MainNoGUI.cpp b/Source/Core/DolphinNoGUI/MainNoGUI.cpp index 9faf1152de27..143d059d04c6 100644 --- a/Source/Core/DolphinNoGUI/MainNoGUI.cpp +++ b/Source/Core/DolphinNoGUI/MainNoGUI.cpp @@ -143,8 +143,7 @@ int main(int argc, char* argv[]) "headless" #ifdef __linux__ , - "fbdev", - "drm" + "fbdev", "drm" #endif #if HAVE_X11 , From 0c523614eabd043b51d6addbb34cb0d6a85ec7e1 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 14:55:22 +0200 Subject: [PATCH 07/26] Update Source/Core/Common/GL/GLInterface/EGLDRM.h Co-authored-by: LC --- Source/Core/Common/GL/GLInterface/EGLDRM.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.h b/Source/Core/Common/GL/GLInterface/EGLDRM.h index 61bb6a7cfe23..9b38f00900cd 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.h +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.h @@ -27,7 +27,7 @@ typedef struct class GLContextEGLDRM : public GLContext { public: - virtual ~GLContextEGLDRM() override; + ~GLContextEGLDRM() override; bool IsHeadless() const override; From 0404543372cbf6da890ccb7bdaa36fc0e135e430 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 14:55:33 +0200 Subject: [PATCH 08/26] Update Source/Core/Common/GL/GLInterface/EGLDRM.cpp Co-authored-by: LC --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index e617592e677d..d341d26f8bca 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -76,7 +76,7 @@ #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 #endif /* EGL_KHR_create_context */ -typedef bool (*egl_accept_config_cb_t)(void *display_data, EGLDisplay dpy, EGLConfig config); +using EGLAcceptConfigCB = bool (*)(void *display_data, EGLDisplay dpy, EGLConfig config); typedef struct gfx_ctx_drm_data { From b66346be056d5b46068b577f227bab54fa6bdaf9 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 14:55:49 +0200 Subject: [PATCH 09/26] Update Source/Core/DolphinNoGUI/PlatformDRM.cpp Co-authored-by: LC --- Source/Core/DolphinNoGUI/PlatformDRM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/DolphinNoGUI/PlatformDRM.cpp b/Source/Core/DolphinNoGUI/PlatformDRM.cpp index 1784aaae4f84..255888ad4cc1 100644 --- a/Source/Core/DolphinNoGUI/PlatformDRM.cpp +++ b/Source/Core/DolphinNoGUI/PlatformDRM.cpp @@ -40,7 +40,7 @@ class PlatformDRM : public Platform private: }; -PlatformDRM::~PlatformDRM() +PlatformDRM::~PlatformDRM() = default; { } From 8a6e26d483df52358d563190274f312a6d5eebbf Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 16:02:21 +0200 Subject: [PATCH 10/26] Run clang-format on EGLDRM --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 1481 +++++++++--------- 1 file changed, 726 insertions(+), 755 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index d341d26f8bca..100e60d1c78e 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -19,28 +19,28 @@ * If not, see . */ -#include -#include #include -#include -#include +#include #include +#include #include +#include +#include +#include +#include #include #include -#include -#include -#include +#include #include #include #include +#include +#include #include #include -#include #include #include -#include #include "Common/GL/GLInterface/EGLDRM.h" #include "Common/Logging/Log.h" @@ -76,43 +76,43 @@ #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 #endif /* EGL_KHR_create_context */ -using EGLAcceptConfigCB = bool (*)(void *display_data, EGLDisplay dpy, EGLConfig config); +using EGLAcceptConfigCB = bool (*)(void* display_data, EGLDisplay dpy, EGLConfig config); typedef struct gfx_ctx_drm_data { - egl_ctx_data_t egl; - int fd; - int interval; - unsigned fb_width; - unsigned fb_height; - - bool core_hw_context_enable; - bool waiting_for_flip; - struct gbm_bo *bo; - struct gbm_bo *next_bo; - struct gbm_surface *gbm_surface; - struct gbm_device *gbm_dev; + egl_ctx_data_t egl; + int fd; + int interval; + unsigned fb_width; + unsigned fb_height; + + bool core_hw_context_enable; + bool waiting_for_flip; + struct gbm_bo* bo; + struct gbm_bo* next_bo; + struct gbm_surface* gbm_surface; + struct gbm_device* gbm_dev; } gfx_ctx_drm_data_t; struct drm_fb { - struct gbm_bo *bo; - uint32_t fb_id; + struct gbm_bo* bo; + uint32_t fb_id; }; /* TODO/FIXME - globals */ static drmEventContext g_drm_evctx; static struct pollfd g_drm_fds; -static uint32_t g_connector_id = 0; -static int g_drm_fd = 0; -static uint32_t g_crtc_id = 0; -static drmModeCrtc *g_orig_crtc = NULL; -static drmModeConnector *g_drm_connector = NULL; -static drmModeModeInfo *g_drm_mode = NULL; +static uint32_t g_connector_id = 0; +static int g_drm_fd = 0; +static uint32_t g_crtc_id = 0; +static drmModeCrtc* g_orig_crtc = NULL; +static drmModeConnector* g_drm_connector = NULL; +static drmModeModeInfo* g_drm_mode = NULL; /* TODO/FIXME - static globals */ -static drmModeRes *g_drm_resources = NULL; -static drmModeEncoder *g_drm_encoder = NULL; +static drmModeRes* g_drm_resources = NULL; +static drmModeEncoder* g_drm_encoder = NULL; static gfx_ctx_drm_data* g_drm = NULL; @@ -124,547 +124,524 @@ bool drm_get_resources(int fd); void drm_setup(int fd); void drm_free(void); bool drm_get_connector(int fd); -float drm_get_refresh_rate(void *data); +float drm_get_refresh_rate(void* data); -static void egl_destroy(egl_ctx_data_t *egl) +static void egl_destroy(egl_ctx_data_t* egl) { - if (egl->dpy) - { - eglMakeCurrent(egl->dpy, - EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (egl->ctx != EGL_NO_CONTEXT) - eglDestroyContext(egl->dpy, egl->ctx); - - if (egl->surf != EGL_NO_SURFACE) - eglDestroySurface(egl->dpy, egl->surf); - eglTerminate(egl->dpy); - } + if (egl->dpy) + { + eglMakeCurrent(egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (egl->ctx != EGL_NO_CONTEXT) + eglDestroyContext(egl->dpy, egl->ctx); - /* Be as careful as possible in deinit. - * If we screw up, any TTY will not restore. - */ + if (egl->surf != EGL_NO_SURFACE) + eglDestroySurface(egl->dpy, egl->surf); + eglTerminate(egl->dpy); + } + + /* Be as careful as possible in deinit. + * If we screw up, any TTY will not restore. + */ - egl->ctx = EGL_NO_CONTEXT; - egl->surf = EGL_NO_SURFACE; - egl->dpy = EGL_NO_DISPLAY; - egl->config = 0; + egl->ctx = EGL_NO_CONTEXT; + egl->surf = EGL_NO_SURFACE; + egl->dpy = EGL_NO_DISPLAY; + egl->config = 0; } -static void egl_swap_buffers(void *data) +static void egl_swap_buffers(void* data) { - egl_ctx_data_t *egl = (egl_ctx_data_t*)data; - if ( egl && - egl->dpy != EGL_NO_DISPLAY && - egl->surf != EGL_NO_SURFACE - ) - { - eglSwapBuffers(egl->dpy, egl->surf); - } + egl_ctx_data_t* egl = (egl_ctx_data_t*)data; + if (egl && egl->dpy != EGL_NO_DISPLAY && egl->surf != EGL_NO_SURFACE) + { + eglSwapBuffers(egl->dpy, egl->surf); + } } -static void egl_set_swap_interval(egl_ctx_data_t *egl, int interval) +static void egl_set_swap_interval(egl_ctx_data_t* egl, int interval) { - /* Can be called before initialization. - * Some contexts require that swap interval - * is known at startup time. - */ - egl->interval = interval; - - if (egl->dpy == EGL_NO_DISPLAY) - return; - if (!eglGetCurrentContext()) - return; - - INFO_LOG(VIDEO, "[EGL]: eglSwapInterval(%u)\n", interval); - if (!eglSwapInterval(egl->dpy, interval)) - { - INFO_LOG(VIDEO, "[EGL]: eglSwapInterval() failed 0x%x.\n", eglGetError()); - } + /* Can be called before initialization. + * Some contexts require that swap interval + * is known at startup time. + */ + egl->interval = interval; + + if (egl->dpy == EGL_NO_DISPLAY) + return; + if (!eglGetCurrentContext()) + return; + + INFO_LOG(VIDEO, "[EGL]: eglSwapInterval(%u)\n", interval); + if (!eglSwapInterval(egl->dpy, interval)) + { + INFO_LOG(VIDEO, "[EGL]: eglSwapInterval() failed 0x%x.\n", eglGetError()); + } } static bool check_egl_version(int minMajorVersion, int minMinorVersion) { - int count; - int major, minor; - const char *str = eglQueryString(EGL_NO_DISPLAY, EGL_VERSION); + int count; + int major, minor; + const char* str = eglQueryString(EGL_NO_DISPLAY, EGL_VERSION); - if (!str) - return false; + if (!str) + return false; - count = sscanf(str, "%d.%d", &major, &minor); - if (count != 2) - return false; + count = sscanf(str, "%d.%d", &major, &minor); + if (count != 2) + return false; - if (major < minMajorVersion) - return false; + if (major < minMajorVersion) + return false; - if (major > minMajorVersion) - return true; + if (major > minMajorVersion) + return true; - if (minor >= minMinorVersion) - return true; + if (minor >= minMinorVersion) + return true; - return false; + return false; } -static bool check_egl_client_extension(const char *name) +static bool check_egl_client_extension(const char* name) { - size_t nameLen; - const char *str = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); - /* The EGL implementation doesn't support client extensions at all. */ - if (!str) - return false; - - nameLen = strlen(name); - while (*str != '\0') - { - /* Use strspn and strcspn to find the start position and length of each - * token in the extension string. Using strtok could also work, but - * that would require allocating a copy of the string. */ - size_t len = strcspn(str, " "); - if (len == nameLen && strncmp(str, name, nameLen) == 0) - return true; - str += len; - str += strspn(str, " "); - } + size_t nameLen; + const char* str = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + /* The EGL implementation doesn't support client extensions at all. */ + if (!str) + return false; + + nameLen = strlen(name); + while (*str != '\0') + { + /* Use strspn and strcspn to find the start position and length of each + * token in the extension string. Using strtok could also work, but + * that would require allocating a copy of the string. */ + size_t len = strcspn(str, " "); + if (len == nameLen && strncmp(str, name, nameLen) == 0) + return true; + str += len; + str += strspn(str, " "); + } - return false; + return false; } -static bool check_egl_display_extension(void* data, const char *name) +static bool check_egl_display_extension(void* data, const char* name) { - size_t nameLen; - egl_ctx_data_t *egl = (egl_ctx_data_t*)data; - if (!egl || egl->dpy == EGL_NO_DISPLAY) - return false; - - const char *str = eglQueryString(egl->dpy, EGL_EXTENSIONS); - /* The EGL implementation doesn't support extensions at all. */ - if (!str) - return false; - - nameLen = strlen(name); - while (*str != '\0') - { - /* Use strspn and strcspn to find the start position and length of each - * token in the extension string. Using strtok could also work, but - * that would require allocating a copy of the string. */ - size_t len = strcspn(str, " "); - if (len == nameLen && strncmp(str, name, nameLen) == 0) - return true; - str += len; - str += strspn(str, " "); - } + size_t nameLen; + egl_ctx_data_t* egl = (egl_ctx_data_t*)data; + if (!egl || egl->dpy == EGL_NO_DISPLAY) + return false; + + const char* str = eglQueryString(egl->dpy, EGL_EXTENSIONS); + /* The EGL implementation doesn't support extensions at all. */ + if (!str) + return false; + + nameLen = strlen(name); + while (*str != '\0') + { + /* Use strspn and strcspn to find the start position and length of each + * token in the extension string. Using strtok could also work, but + * that would require allocating a copy of the string. */ + size_t len = strcspn(str, " "); + if (len == nameLen && strncmp(str, name, nameLen) == 0) + return true; + str += len; + str += strspn(str, " "); + } - return false; + return false; } -static EGLDisplay get_egl_display(EGLenum platform, void *native) +static EGLDisplay get_egl_display(EGLenum platform, void* native) { - if (platform != EGL_NONE) - { - /* If the client library supports at least EGL 1.5, then we can call - * eglGetPlatformDisplay. Otherwise, see if eglGetPlatformDisplayEXT - * is available. */ + if (platform != EGL_NONE) + { + /* If the client library supports at least EGL 1.5, then we can call + * eglGetPlatformDisplay. Otherwise, see if eglGetPlatformDisplayEXT + * is available. */ #if defined(EGL_VERSION_1_5) - if (check_egl_version(1, 5)) + if (check_egl_version(1, 5)) + { + typedef EGLDisplay(EGLAPIENTRY * pfn_eglGetPlatformDisplay)( + EGLenum platform, void* native_display, const EGLAttrib* attrib_list); + pfn_eglGetPlatformDisplay ptr_eglGetPlatformDisplay; + + INFO_LOG(VIDEO, "[EGL] Found EGL client version >= 1.5, trying eglGetPlatformDisplay\n"); + ptr_eglGetPlatformDisplay = + (pfn_eglGetPlatformDisplay)eglGetProcAddress("eglGetPlatformDisplay"); + + if (ptr_eglGetPlatformDisplay) { - typedef EGLDisplay (EGLAPIENTRY * pfn_eglGetPlatformDisplay) - (EGLenum platform, void *native_display, const EGLAttrib *attrib_list); - pfn_eglGetPlatformDisplay ptr_eglGetPlatformDisplay; - - INFO_LOG(VIDEO, "[EGL] Found EGL client version >= 1.5, trying eglGetPlatformDisplay\n"); - ptr_eglGetPlatformDisplay = (pfn_eglGetPlatformDisplay) - eglGetProcAddress("eglGetPlatformDisplay"); - - if (ptr_eglGetPlatformDisplay) - { - EGLDisplay dpy = ptr_eglGetPlatformDisplay(platform, native, NULL); - if (dpy != EGL_NO_DISPLAY) - return dpy; - } + EGLDisplay dpy = ptr_eglGetPlatformDisplay(platform, native, NULL); + if (dpy != EGL_NO_DISPLAY) + return dpy; } + } #endif /* defined(EGL_VERSION_1_5) */ #if defined(EGL_EXT_platform_base) - if (check_egl_client_extension("EGL_EXT_platform_base")) + if (check_egl_client_extension("EGL_EXT_platform_base")) + { + PFNEGLGETPLATFORMDISPLAYEXTPROC ptr_eglGetPlatformDisplayEXT; + + INFO_LOG(VIDEO, "[EGL] Found EGL_EXT_platform_base, trying eglGetPlatformDisplayEXT\n"); + ptr_eglGetPlatformDisplayEXT = + (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT"); + + if (ptr_eglGetPlatformDisplayEXT) { - PFNEGLGETPLATFORMDISPLAYEXTPROC ptr_eglGetPlatformDisplayEXT; - - INFO_LOG(VIDEO, "[EGL] Found EGL_EXT_platform_base, trying eglGetPlatformDisplayEXT\n"); - ptr_eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) - eglGetProcAddress("eglGetPlatformDisplayEXT"); - - if (ptr_eglGetPlatformDisplayEXT) - { - EGLDisplay dpy = ptr_eglGetPlatformDisplayEXT(platform, native, NULL); - if (dpy != EGL_NO_DISPLAY) - return dpy; - } + EGLDisplay dpy = ptr_eglGetPlatformDisplayEXT(platform, native, NULL); + if (dpy != EGL_NO_DISPLAY) + return dpy; } + } #endif /* defined(EGL_EXT_platform_base) */ - } + } - /* Either the caller didn't provide a platform type, or the EGL - * implementation doesn't support eglGetPlatformDisplay. In this case, try - * eglGetDisplay and hope for the best. */ - INFO_LOG(VIDEO, "[EGL] Falling back to eglGetDisplay\n"); - return eglGetDisplay((EGLNativeDisplayType) native); + /* Either the caller didn't provide a platform type, or the EGL + * implementation doesn't support eglGetPlatformDisplay. In this case, try + * eglGetDisplay and hope for the best. */ + INFO_LOG(VIDEO, "[EGL] Falling back to eglGetDisplay\n"); + return eglGetDisplay((EGLNativeDisplayType)native); } -static bool egl_get_native_visual_id(egl_ctx_data_t *egl, EGLint *value) +static bool egl_get_native_visual_id(egl_ctx_data_t* egl, EGLint* value) { - if (!eglGetConfigAttrib(egl->dpy, egl->config, - EGL_NATIVE_VISUAL_ID, value)) - { - INFO_LOG(VIDEO, "[EGL]: egl_get_native_visual_id failed.\n"); - return false; - } + if (!eglGetConfigAttrib(egl->dpy, egl->config, EGL_NATIVE_VISUAL_ID, value)) + { + INFO_LOG(VIDEO, "[EGL]: egl_get_native_visual_id failed.\n"); + return false; + } - return true; + return true; } -static bool egl_init_context_common( - egl_ctx_data_t *egl, EGLint *count, - const EGLint *attrib_ptr, - egl_accept_config_cb_t cb, - void *display_data) +static bool egl_init_context_common(egl_ctx_data_t* egl, EGLint* count, const EGLint* attrib_ptr, + egl_accept_config_cb_t cb, void* display_data) { - EGLint i; - EGLint matched = 0; - EGLConfig *configs = NULL; - if (!egl) - return false; + EGLint i; + EGLint matched = 0; + EGLConfig* configs = NULL; + if (!egl) + return false; - if (!eglGetConfigs(egl->dpy, NULL, 0, count) || *count < 1) - { - INFO_LOG(VIDEO, "[EGL]: No configs to choose from.\n"); - return false; - } + if (!eglGetConfigs(egl->dpy, NULL, 0, count) || *count < 1) + { + INFO_LOG(VIDEO, "[EGL]: No configs to choose from.\n"); + return false; + } - configs = (EGLConfig*)malloc(*count * sizeof(*configs)); - if (!configs) - return false; + configs = (EGLConfig*)malloc(*count * sizeof(*configs)); + if (!configs) + return false; - if (!eglChooseConfig(egl->dpy, attrib_ptr, - configs, *count, &matched) || !matched) - { - INFO_LOG(VIDEO, "[EGL]: No EGL configs with appropriate attributes.\n"); - return false; - } + if (!eglChooseConfig(egl->dpy, attrib_ptr, configs, *count, &matched) || !matched) + { + INFO_LOG(VIDEO, "[EGL]: No EGL configs with appropriate attributes.\n"); + return false; + } - for (i = 0; i < *count; i++) - { - if (!cb || cb(display_data, egl->dpy, configs[i])) - { - egl->config = configs[i]; - break; - } - } + for (i = 0; i < *count; i++) + { + if (!cb || cb(display_data, egl->dpy, configs[i])) + { + egl->config = configs[i]; + break; + } + } - free(configs); + free(configs); - if (i == *count) - { - INFO_LOG(VIDEO, "[EGL]: No EGL config found which satifies requirements.\n"); - return false; - } + if (i == *count) + { + INFO_LOG(VIDEO, "[EGL]: No EGL config found which satifies requirements.\n"); + return false; + } - return true; + return true; } - -static bool egl_init_context(egl_ctx_data_t *egl, - EGLenum platform, - void *display_data, - EGLint *major, EGLint *minor, - EGLint *count, const EGLint *attrib_ptr, - egl_accept_config_cb_t cb) +static bool egl_init_context(egl_ctx_data_t* egl, EGLenum platform, void* display_data, + EGLint* major, EGLint* minor, EGLint* count, const EGLint* attrib_ptr, + egl_accept_config_cb_t cb) { - EGLDisplay dpy = get_egl_display(platform, display_data); + EGLDisplay dpy = get_egl_display(platform, display_data); - if (dpy == EGL_NO_DISPLAY) - { - INFO_LOG(VIDEO, "[EGL]: Couldn't get EGL display.\n"); - return false; - } + if (dpy == EGL_NO_DISPLAY) + { + INFO_LOG(VIDEO, "[EGL]: Couldn't get EGL display.\n"); + return false; + } - egl->dpy = dpy; + egl->dpy = dpy; - if (!eglInitialize(egl->dpy, major, minor)) - return false; + if (!eglInitialize(egl->dpy, major, minor)) + return false; - INFO_LOG(VIDEO, "[EGL]: EGL version: %d.%d\n", *major, *minor); + INFO_LOG(VIDEO, "[EGL]: EGL version: %d.%d\n", *major, *minor); - return egl_init_context_common(egl, count, attrib_ptr, cb, - display_data); + return egl_init_context_common(egl, count, attrib_ptr, cb, display_data); } -static bool egl_create_context(egl_ctx_data_t *egl, const EGLint *egl_attribs) +static bool egl_create_context(egl_ctx_data_t* egl, const EGLint* egl_attribs) { - EGLContext ctx = eglCreateContext(egl->dpy, egl->config, EGL_NO_CONTEXT, - egl_attribs); + EGLContext ctx = eglCreateContext(egl->dpy, egl->config, EGL_NO_CONTEXT, egl_attribs); - if (ctx == EGL_NO_CONTEXT) - return false; + if (ctx == EGL_NO_CONTEXT) + return false; - egl->ctx = ctx; + egl->ctx = ctx; - return true; + return true; } -static bool egl_create_surface(egl_ctx_data_t *egl, void *native_window) +static bool egl_create_surface(egl_ctx_data_t* egl, void* native_window) { - EGLint window_attribs[] = { - EGL_RENDER_BUFFER, EGL_BACK_BUFFER, - EGL_NONE, - }; + EGLint window_attribs[] = { + EGL_RENDER_BUFFER, + EGL_BACK_BUFFER, + EGL_NONE, + }; - egl->surf = eglCreateWindowSurface(egl->dpy, egl->config, (NativeWindowType)native_window, window_attribs); + egl->surf = eglCreateWindowSurface(egl->dpy, egl->config, (NativeWindowType)native_window, + window_attribs); - if (egl->surf == EGL_NO_SURFACE) - return false; + if (egl->surf == EGL_NO_SURFACE) + return false; - /* Connect the context to the surface. */ - if (!eglMakeCurrent(egl->dpy, egl->surf, egl->surf, egl->ctx)) - return false; + /* Connect the context to the surface. */ + if (!eglMakeCurrent(egl->dpy, egl->surf, egl->surf, egl->ctx)) + return false; - INFO_LOG(VIDEO, "[EGL]: Current context: %p.\n", (void*)eglGetCurrentContext()); + INFO_LOG(VIDEO, "[EGL]: Current context: %p.\n", (void*)eglGetCurrentContext()); - return true; + return true; } static bool drm_wait_flip(int timeout) { - g_drm_fds.revents = 0; + g_drm_fds.revents = 0; - if (poll(&g_drm_fds, 1, timeout) < 0) - return false; + if (poll(&g_drm_fds, 1, timeout) < 0) + return false; - if (g_drm_fds.revents & (POLLHUP | POLLERR)) - return false; + if (g_drm_fds.revents & (POLLHUP | POLLERR)) + return false; - if (g_drm_fds.revents & POLLIN) - { - drmHandleEvent(g_drm_fd, &g_drm_evctx); - return true; - } + if (g_drm_fds.revents & POLLIN) + { + drmHandleEvent(g_drm_fd, &g_drm_evctx); + return true; + } - return false; + return false; } /* Restore the original CRTC. */ void drm_restore_crtc(void) { - if (!g_orig_crtc) - return; + if (!g_orig_crtc) + return; - drmModeSetCrtc(g_drm_fd, g_orig_crtc->crtc_id, - g_orig_crtc->buffer_id, - g_orig_crtc->x, - g_orig_crtc->y, - &g_connector_id, 1, &g_orig_crtc->mode); + drmModeSetCrtc(g_drm_fd, g_orig_crtc->crtc_id, g_orig_crtc->buffer_id, g_orig_crtc->x, + g_orig_crtc->y, &g_connector_id, 1, &g_orig_crtc->mode); - drmModeFreeCrtc(g_orig_crtc); - g_orig_crtc = NULL; + drmModeFreeCrtc(g_orig_crtc); + g_orig_crtc = NULL; } bool drm_get_resources(int fd) { - g_drm_resources = drmModeGetResources(fd); - if (!g_drm_resources) - { - INFO_LOG(VIDEO, "[DRM]: Couldn't get device resources.\n"); - return false; - } + g_drm_resources = drmModeGetResources(fd); + if (!g_drm_resources) + { + INFO_LOG(VIDEO, "[DRM]: Couldn't get device resources.\n"); + return false; + } - return true; + return true; } bool drm_get_connector(int fd) { - unsigned i; - unsigned monitor_index_count = 0; - unsigned monitor = 1; + unsigned i; + unsigned monitor_index_count = 0; + unsigned monitor = 1; - /* Enumerate all connectors. */ + /* Enumerate all connectors. */ - INFO_LOG(VIDEO, "[DRM]: Found %d connectors.\n", g_drm_resources->count_connectors); + INFO_LOG(VIDEO, "[DRM]: Found %d connectors.\n", g_drm_resources->count_connectors); - for (i = 0; (int)i < g_drm_resources->count_connectors; i++) - { - drmModeConnectorPtr conn = drmModeGetConnector( - fd, g_drm_resources->connectors[i]); + for (i = 0; (int)i < g_drm_resources->count_connectors; i++) + { + drmModeConnectorPtr conn = drmModeGetConnector(fd, g_drm_resources->connectors[i]); - if (conn) + if (conn) + { + bool connected = conn->connection == DRM_MODE_CONNECTED; + INFO_LOG(VIDEO, "[DRM]: Connector %d connected: %s\n", i, connected ? "yes" : "no"); + INFO_LOG(VIDEO, "[DRM]: Connector %d has %d modes.\n", i, conn->count_modes); + if (connected && conn->count_modes > 0) { - bool connected = conn->connection == DRM_MODE_CONNECTED; - INFO_LOG(VIDEO, "[DRM]: Connector %d connected: %s\n", i, connected ? "yes" : "no"); - INFO_LOG(VIDEO, "[DRM]: Connector %d has %d modes.\n", i, conn->count_modes); - if (connected && conn->count_modes > 0) - { - monitor_index_count++; - INFO_LOG(VIDEO, "[DRM]: Connector %d assigned to monitor index: #%u.\n", i, monitor_index_count); - } - drmModeFreeConnector(conn); + monitor_index_count++; + INFO_LOG(VIDEO, "[DRM]: Connector %d assigned to monitor index: #%u.\n", i, + monitor_index_count); } - } + drmModeFreeConnector(conn); + } + } - monitor_index_count = 0; + monitor_index_count = 0; - for (i = 0; (int)i < g_drm_resources->count_connectors; i++) - { - g_drm_connector = drmModeGetConnector(fd, - g_drm_resources->connectors[i]); + for (i = 0; (int)i < g_drm_resources->count_connectors; i++) + { + g_drm_connector = drmModeGetConnector(fd, g_drm_resources->connectors[i]); - if (!g_drm_connector) - continue; - if (g_drm_connector->connection == DRM_MODE_CONNECTED - && g_drm_connector->count_modes > 0) - { - monitor_index_count++; - if (monitor_index_count == monitor) - break; - } + if (!g_drm_connector) + continue; + if (g_drm_connector->connection == DRM_MODE_CONNECTED && g_drm_connector->count_modes > 0) + { + monitor_index_count++; + if (monitor_index_count == monitor) + break; + } - drmModeFreeConnector(g_drm_connector); - g_drm_connector = NULL; - } + drmModeFreeConnector(g_drm_connector); + g_drm_connector = NULL; + } - if (!g_drm_connector) - { - INFO_LOG(VIDEO, "[DRM]: Couldn't get device connector.\n"); - return false; - } - return true; + if (!g_drm_connector) + { + INFO_LOG(VIDEO, "[DRM]: Couldn't get device connector.\n"); + return false; + } + return true; } bool drm_get_encoder(int fd) { - unsigned i; + unsigned i; - for (i = 0; (int)i < g_drm_resources->count_encoders; i++) - { - g_drm_encoder = drmModeGetEncoder(fd, g_drm_resources->encoders[i]); + for (i = 0; (int)i < g_drm_resources->count_encoders; i++) + { + g_drm_encoder = drmModeGetEncoder(fd, g_drm_resources->encoders[i]); - if (!g_drm_encoder) - continue; + if (!g_drm_encoder) + continue; - if (g_drm_encoder->encoder_id == g_drm_connector->encoder_id) - break; + if (g_drm_encoder->encoder_id == g_drm_connector->encoder_id) + break; - drmModeFreeEncoder(g_drm_encoder); - g_drm_encoder = NULL; - } + drmModeFreeEncoder(g_drm_encoder); + g_drm_encoder = NULL; + } - if (!g_drm_encoder) - { - INFO_LOG(VIDEO, "[DRM]: Couldn't find DRM encoder.\n"); - return false; - } + if (!g_drm_encoder) + { + INFO_LOG(VIDEO, "[DRM]: Couldn't find DRM encoder.\n"); + return false; + } - for (i = 0; (int)i < g_drm_connector->count_modes; i++) - { - INFO_LOG(VIDEO, "[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", - i, - g_drm_connector->modes[i].name, - g_drm_connector->modes[i].hdisplay, - g_drm_connector->modes[i].vdisplay, - g_drm_connector->modes[i].vrefresh); - } + for (i = 0; (int)i < g_drm_connector->count_modes; i++) + { + INFO_LOG(VIDEO, "[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", i, g_drm_connector->modes[i].name, + g_drm_connector->modes[i].hdisplay, g_drm_connector->modes[i].vdisplay, + g_drm_connector->modes[i].vrefresh); + } - return true; + return true; } void drm_setup(int fd) { - g_crtc_id = g_drm_encoder->crtc_id; - g_connector_id = g_drm_connector->connector_id; - g_orig_crtc = drmModeGetCrtc(fd, g_crtc_id); - if (!g_orig_crtc) - INFO_LOG(VIDEO, "[DRM]: Cannot find original CRTC.\n"); + g_crtc_id = g_drm_encoder->crtc_id; + g_connector_id = g_drm_connector->connector_id; + g_orig_crtc = drmModeGetCrtc(fd, g_crtc_id); + if (!g_orig_crtc) + INFO_LOG(VIDEO, "[DRM]: Cannot find original CRTC.\n"); } -float drm_get_refresh_rate(void *data) +float drm_get_refresh_rate(void* data) { - float refresh_rate = 0.0f; + float refresh_rate = 0.0f; - if (g_drm_mode) - { - refresh_rate = g_drm_mode->clock * 1000.0f / g_drm_mode->htotal / g_drm_mode->vtotal; - } + if (g_drm_mode) + { + refresh_rate = g_drm_mode->clock * 1000.0f / g_drm_mode->htotal / g_drm_mode->vtotal; + } - return refresh_rate; + return refresh_rate; } void drm_free(void) { - if (g_drm_encoder) - drmModeFreeEncoder(g_drm_encoder); - if (g_drm_connector) - drmModeFreeConnector(g_drm_connector); - if (g_drm_resources) - drmModeFreeResources(g_drm_resources); - - memset(&g_drm_fds, 0, sizeof(struct pollfd)); - memset(&g_drm_evctx, 0, sizeof(drmEventContext)); - - g_drm_encoder = NULL; - g_drm_connector = NULL; - g_drm_resources = NULL; + if (g_drm_encoder) + drmModeFreeEncoder(g_drm_encoder); + if (g_drm_connector) + drmModeFreeConnector(g_drm_connector); + if (g_drm_resources) + drmModeFreeResources(g_drm_resources); + + memset(&g_drm_fds, 0, sizeof(struct pollfd)); + memset(&g_drm_evctx, 0, sizeof(drmEventContext)); + + g_drm_encoder = NULL; + g_drm_connector = NULL; + g_drm_resources = NULL; } -static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data) +static void drm_fb_destroy_callback(struct gbm_bo* bo, void* data) { - struct drm_fb *fb = (struct drm_fb*)data; + struct drm_fb* fb = (struct drm_fb*)data; - if (fb && fb->fb_id) - drmModeRmFB(g_drm_fd, fb->fb_id); + if (fb && fb->fb_id) + drmModeRmFB(g_drm_fd, fb->fb_id); - free(fb); + free(fb); } -static struct drm_fb *drm_fb_get_from_bo(struct gbm_bo *bo) +static struct drm_fb* drm_fb_get_from_bo(struct gbm_bo* bo) { - int ret; - unsigned width, height, stride, handle; - struct drm_fb *fb = (struct drm_fb*)calloc(1, sizeof(*fb)); + int ret; + unsigned width, height, stride, handle; + struct drm_fb* fb = (struct drm_fb*)calloc(1, sizeof(*fb)); - fb->bo = bo; + fb->bo = bo; - width = gbm_bo_get_width(bo); - height = gbm_bo_get_height(bo); - stride = gbm_bo_get_stride(bo); - handle = gbm_bo_get_handle(bo).u32; + width = gbm_bo_get_width(bo); + height = gbm_bo_get_height(bo); + stride = gbm_bo_get_stride(bo); + handle = gbm_bo_get_handle(bo).u32; - INFO_LOG(VIDEO, "[KMS]: New FB: %ux%u (stride: %u).\n", - width, height, stride); + INFO_LOG(VIDEO, "[KMS]: New FB: %ux%u (stride: %u).\n", width, height, stride); - ret = drmModeAddFB(g_drm_fd, width, height, 24, 32, - stride, handle, &fb->fb_id); - if (ret < 0) - goto error; + ret = drmModeAddFB(g_drm_fd, width, height, 24, 32, stride, handle, &fb->fb_id); + if (ret < 0) + goto error; - gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback); - return fb; + gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback); + return fb; error: - INFO_LOG(VIDEO, "[KMS]: Failed to create FB: %s\n", strerror(errno)); - free(fb); - return NULL; + INFO_LOG(VIDEO, "[KMS]: Failed to create FB: %s\n", strerror(errno)); + free(fb); + return NULL; } -static void gfx_ctx_drm_swap_interval(void *data, int interval) +static void gfx_ctx_drm_swap_interval(void* data, int interval) { - gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; - drm->interval = interval; + gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)data; + drm->interval = interval; - if (interval > 1) - INFO_LOG(VIDEO, "[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); + if (interval > 1) + INFO_LOG(VIDEO, + "[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); } -static void drm_flip_handler(int fd, unsigned frame, - unsigned sec, unsigned usec, void *data) +static void drm_flip_handler(int fd, unsigned frame, unsigned sec, unsigned usec, void* data) { #if 0 static unsigned first_page_flip; @@ -684,444 +661,434 @@ static void drm_flip_handler(int fd, unsigned frame, last_page_flip = frame; #endif - *(bool*)data = false; + *(bool*)data = false; } -static bool gfx_ctx_drm_wait_flip(gfx_ctx_drm_data_t *drm, bool block) +static bool gfx_ctx_drm_wait_flip(gfx_ctx_drm_data_t* drm, bool block) { - int timeout = 0; + int timeout = 0; - if (!drm->waiting_for_flip) - return false; + if (!drm->waiting_for_flip) + return false; - if (block) - timeout = -1; + if (block) + timeout = -1; - while (drm->waiting_for_flip) - { - if (!drm_wait_flip(timeout)) - break; - } + while (drm->waiting_for_flip) + { + if (!drm_wait_flip(timeout)) + break; + } - if (drm->waiting_for_flip) - { INFO_LOG(VIDEO, "\nwait flip 2"); return true; } + if (drm->waiting_for_flip) + { + INFO_LOG(VIDEO, "\nwait flip 2"); + return true; + } - /* Page flip has taken place. */ + /* Page flip has taken place. */ - /* This buffer is not on-screen anymore. Release it to GBM. */ - gbm_surface_release_buffer(drm->gbm_surface, drm->bo); - /* This buffer is being shown now. */ - drm->bo = drm->next_bo; - return false; + /* This buffer is not on-screen anymore. Release it to GBM. */ + gbm_surface_release_buffer(drm->gbm_surface, drm->bo); + /* This buffer is being shown now. */ + drm->bo = drm->next_bo; + return false; } -static bool gfx_ctx_drm_queue_flip(gfx_ctx_drm_data_t *drm) +static bool gfx_ctx_drm_queue_flip(gfx_ctx_drm_data_t* drm) { - struct drm_fb *fb = NULL; + struct drm_fb* fb = NULL; - drm->next_bo = gbm_surface_lock_front_buffer(drm->gbm_surface); - fb = (struct drm_fb*)gbm_bo_get_user_data(drm->next_bo); + drm->next_bo = gbm_surface_lock_front_buffer(drm->gbm_surface); + fb = (struct drm_fb*)gbm_bo_get_user_data(drm->next_bo); - if (!fb) - fb = (struct drm_fb*)drm_fb_get_from_bo(drm->next_bo); + if (!fb) + fb = (struct drm_fb*)drm_fb_get_from_bo(drm->next_bo); - if (drmModePageFlip(g_drm_fd, g_crtc_id, fb->fb_id, - DRM_MODE_PAGE_FLIP_EVENT, &drm->waiting_for_flip) == 0) - return true; + if (drmModePageFlip(g_drm_fd, g_crtc_id, fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, + &drm->waiting_for_flip) == 0) + return true; - /* Failed to queue page flip. */ - INFO_LOG(VIDEO, "\nFailed to queue page flip\n"); - return false; + /* Failed to queue page flip. */ + INFO_LOG(VIDEO, "\nFailed to queue page flip\n"); + return false; } -static void gfx_ctx_drm_swap_buffers(void *data) +static void gfx_ctx_drm_swap_buffers(void* data) { - gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; - unsigned max_swapchain_images = 2; //settings->uints.video_max_swapchain_images; + gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)data; + unsigned max_swapchain_images = 2; // settings->uints.video_max_swapchain_images; - egl_swap_buffers(&drm->egl); + egl_swap_buffers(&drm->egl); - /* I guess we have to wait for flip to have taken - * place before another flip can be queued up. - * - * If true, we are still waiting for a flip - * (nonblocking mode, so just drop the frame). */ - if (gfx_ctx_drm_wait_flip(drm, drm->interval)) - { INFO_LOG(VIDEO, "\nwait flip"); return; } + /* I guess we have to wait for flip to have taken + * place before another flip can be queued up. + * + * If true, we are still waiting for a flip + * (nonblocking mode, so just drop the frame). */ + if (gfx_ctx_drm_wait_flip(drm, drm->interval)) + { + INFO_LOG(VIDEO, "\nwait flip"); + return; + } - drm->waiting_for_flip = gfx_ctx_drm_queue_flip(drm); + drm->waiting_for_flip = gfx_ctx_drm_queue_flip(drm); - /* Triple-buffered page flips */ - if (max_swapchain_images >= 3 && - gbm_surface_has_free_buffers(drm->gbm_surface)) - return; + /* Triple-buffered page flips */ + if (max_swapchain_images >= 3 && gbm_surface_has_free_buffers(drm->gbm_surface)) + return; - gfx_ctx_drm_wait_flip(drm, true); + gfx_ctx_drm_wait_flip(drm, true); } -static void gfx_ctx_drm_get_video_size(void *data, - unsigned *width, unsigned *height) +static void gfx_ctx_drm_get_video_size(void* data, unsigned* width, unsigned* height) { - gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)data; - if (!drm) - { - INFO_LOG(VIDEO, "\nCannot get drm video size\n"); - return; - } + if (!drm) + { + INFO_LOG(VIDEO, "\nCannot get drm video size\n"); + return; + } - *width = drm->fb_width; - *height = drm->fb_height; + *width = drm->fb_width; + *height = drm->fb_height; } -static void free_drm_resources(gfx_ctx_drm_data_t *drm) +static void free_drm_resources(gfx_ctx_drm_data_t* drm) { - if (!drm) - return; + if (!drm) + return; - /* Restore original CRTC. */ - drm_restore_crtc(); + /* Restore original CRTC. */ + drm_restore_crtc(); - if (drm->gbm_surface) - gbm_surface_destroy(drm->gbm_surface); + if (drm->gbm_surface) + gbm_surface_destroy(drm->gbm_surface); - if (drm->gbm_dev) - gbm_device_destroy(drm->gbm_dev); + if (drm->gbm_dev) + gbm_device_destroy(drm->gbm_dev); - drm_free(); + drm_free(); - if (drm->fd >= 0) - { - if (g_drm_fd >= 0) - { - drmDropMaster(g_drm_fd); - close(drm->fd); - } - } + if (drm->fd >= 0) + { + if (g_drm_fd >= 0) + { + drmDropMaster(g_drm_fd); + close(drm->fd); + } + } - drm->gbm_surface = NULL; - drm->gbm_dev = NULL; - g_drm_fd = -1; + drm->gbm_surface = NULL; + drm->gbm_dev = NULL; + g_drm_fd = -1; } -static void gfx_ctx_drm_destroy_resources(gfx_ctx_drm_data_t *drm) +static void gfx_ctx_drm_destroy_resources(gfx_ctx_drm_data_t* drm) { - if (!drm) - return; + if (!drm) + return; - /* Make sure we acknowledge all page-flips. */ - gfx_ctx_drm_wait_flip(drm, true); + /* Make sure we acknowledge all page-flips. */ + gfx_ctx_drm_wait_flip(drm, true); - egl_destroy(&drm->egl); + egl_destroy(&drm->egl); - free_drm_resources(drm); + free_drm_resources(drm); - g_drm_mode = NULL; - g_crtc_id = 0; - g_connector_id = 0; + g_drm_mode = NULL; + g_crtc_id = 0; + g_connector_id = 0; - drm->fb_width = 0; - drm->fb_height = 0; + drm->fb_width = 0; + drm->fb_height = 0; - drm->bo = NULL; - drm->next_bo = NULL; + drm->bo = NULL; + drm->next_bo = NULL; } -static void *gfx_ctx_drm_init() +static void* gfx_ctx_drm_init() { - int fd, i; - unsigned monitor_index; - unsigned gpu_index = 0; - const char *gpu = NULL; - gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)calloc(1, sizeof(gfx_ctx_drm_data_t)); + int fd, i; + unsigned monitor_index; + unsigned gpu_index = 0; + const char* gpu = NULL; + gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)calloc(1, sizeof(gfx_ctx_drm_data_t)); - if (!drm) - return NULL; - drm->fd = -1; + if (!drm) + return NULL; + drm->fd = -1; - free_drm_resources(drm); + free_drm_resources(drm); - drm->fd = open("/dev/dri/card0", O_RDWR); - if (drm->fd < 0) - { - INFO_LOG(VIDEO, "[KMS]: Couldn't open DRM device.\n"); - return nullptr; - } + drm->fd = open("/dev/dri/card0", O_RDWR); + if (drm->fd < 0) + { + INFO_LOG(VIDEO, "[KMS]: Couldn't open DRM device.\n"); + return nullptr; + } - fd = drm->fd; + fd = drm->fd; - if (!drm_get_resources(fd)) - { - INFO_LOG(VIDEO, "[KMS]: drm_get_resources failed\n"); - return nullptr; - } + if (!drm_get_resources(fd)) + { + INFO_LOG(VIDEO, "[KMS]: drm_get_resources failed\n"); + return nullptr; + } - if (!drm_get_connector(fd)) - { - INFO_LOG(VIDEO, "[KMS]: drm_get_connector failed\n"); - return nullptr; - } + if (!drm_get_connector(fd)) + { + INFO_LOG(VIDEO, "[KMS]: drm_get_connector failed\n"); + return nullptr; + } - if (!drm_get_encoder(fd)) - { - INFO_LOG(VIDEO, "[KMS]: drm_get_encoder failed\n"); - return nullptr; - } + if (!drm_get_encoder(fd)) + { + INFO_LOG(VIDEO, "[KMS]: drm_get_encoder failed\n"); + return nullptr; + } - drm_setup(fd); + drm_setup(fd); - /* Choose the optimal video mode for get_video_size(): - - the current video mode from the CRTC - - otherwise pick first connector mode */ - if (g_orig_crtc->mode_valid) - { - drm->fb_width = g_orig_crtc->mode.hdisplay; - drm->fb_height = g_orig_crtc->mode.vdisplay; - } - else - { - drm->fb_width = g_drm_connector->modes[0].hdisplay; - drm->fb_height = g_drm_connector->modes[0].vdisplay; - } + /* Choose the optimal video mode for get_video_size(): + - the current video mode from the CRTC + - otherwise pick first connector mode */ + if (g_orig_crtc->mode_valid) + { + drm->fb_width = g_orig_crtc->mode.hdisplay; + drm->fb_height = g_orig_crtc->mode.vdisplay; + } + else + { + drm->fb_width = g_drm_connector->modes[0].hdisplay; + drm->fb_height = g_drm_connector->modes[0].vdisplay; + } - drmSetMaster(g_drm_fd); + drmSetMaster(g_drm_fd); - drm->gbm_dev = gbm_create_device(fd); + drm->gbm_dev = gbm_create_device(fd); - if (!drm->gbm_dev) - { - INFO_LOG(VIDEO, "[KMS]: Couldn't create GBM device.\n"); - return nullptr; - } + if (!drm->gbm_dev) + { + INFO_LOG(VIDEO, "[KMS]: Couldn't create GBM device.\n"); + return nullptr; + } - /* Setup the flip handler. */ - g_drm_fds.fd = fd; - g_drm_fds.events = POLLIN; - g_drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; - g_drm_evctx.page_flip_handler = drm_flip_handler; + /* Setup the flip handler. */ + g_drm_fds.fd = fd; + g_drm_fds.events = POLLIN; + g_drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; + g_drm_evctx.page_flip_handler = drm_flip_handler; - g_drm_fd = fd; + g_drm_fd = fd; - return drm; + return drm; error: - gfx_ctx_drm_destroy_resources(drm); + gfx_ctx_drm_destroy_resources(drm); - if (drm) - free(drm); + if (drm) + free(drm); - return NULL; + return NULL; } -static EGLint *gfx_ctx_drm_egl_fill_attribs( - gfx_ctx_drm_data_t *drm, EGLint *attr) +static EGLint* gfx_ctx_drm_egl_fill_attribs(gfx_ctx_drm_data_t* drm, EGLint* attr) { - *attr++ = EGL_CONTEXT_CLIENT_VERSION; - *attr++ = drm->egl.major ? (EGLint)drm->egl.major : 2; + *attr++ = EGL_CONTEXT_CLIENT_VERSION; + *attr++ = drm->egl.major ? (EGLint)drm->egl.major : 2; #ifdef EGL_KHR_create_context - if (drm->egl.minor > 0) - { - *attr++ = EGL_CONTEXT_MINOR_VERSION_KHR; - *attr++ = drm->egl.minor; - } + if (drm->egl.minor > 0) + { + *attr++ = EGL_CONTEXT_MINOR_VERSION_KHR; + *attr++ = drm->egl.minor; + } #endif - *attr = EGL_NONE; - return attr; + *attr = EGL_NONE; + return attr; } -static bool gbm_choose_xrgb8888_cb(void *display_data, EGLDisplay dpy, EGLConfig config) +static bool gbm_choose_xrgb8888_cb(void* display_data, EGLDisplay dpy, EGLConfig config) { - EGLint r, g, b, id; - (void)display_data; + EGLint r, g, b, id; + (void)display_data; - /* Makes sure we have 8 bit color. */ - if (!eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r)) - return false; - if (!eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g)) - return false; - if (!eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b)) - return false; + /* Makes sure we have 8 bit color. */ + if (!eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r)) + return false; + if (!eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g)) + return false; + if (!eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b)) + return false; - if (r != 8 || g != 8 || b != 8) - return false; + if (r != 8 || g != 8 || b != 8) + return false; - if (!eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &id)) - return false; + if (!eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &id)) + return false; - return id == GBM_FORMAT_XRGB8888; + return id == GBM_FORMAT_XRGB8888; } -#define DRM_EGL_ATTRIBS_BASE \ - EGL_SURFACE_TYPE, 0/*EGL_WINDOW_BIT*/, \ - EGL_RED_SIZE, 8, \ - EGL_GREEN_SIZE, 8, \ - EGL_BLUE_SIZE, 8, \ - EGL_ALPHA_SIZE, 0, \ - EGL_DEPTH_SIZE, 0 +#define DRM_EGL_ATTRIBS_BASE \ + EGL_SURFACE_TYPE, 0 /*EGL_WINDOW_BIT*/, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, \ + EGL_ALPHA_SIZE, 0, EGL_DEPTH_SIZE, 0 #ifdef EGL_KHR_create_context - static const EGLint egl_attribs_gles3[] = { - DRM_EGL_ATTRIBS_BASE, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, - EGL_NONE, - }; +static const EGLint egl_attribs_gles3[] = { + DRM_EGL_ATTRIBS_BASE, + EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES3_BIT_KHR, + EGL_NONE, +}; #endif -static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t *drm) +static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t* drm) { - const EGLint *attrib_ptr = NULL; - EGLint major; - EGLint minor; - EGLint n; - EGLint egl_attribs[16]; - EGLint *egl_attribs_ptr = NULL; - EGLint *attr = NULL; - - attrib_ptr = egl_attribs_gles3; - - if (!egl_init_context(&drm->egl, EGL_PLATFORM_GBM_KHR, - (EGLNativeDisplayType)drm->gbm_dev, &major, - &minor, &n, attrib_ptr, gbm_choose_xrgb8888_cb)) - { - INFO_LOG(VIDEO, "\n[EGL] Cannot init context error 0x%x",eglGetError()); - goto error; - } - attr = gfx_ctx_drm_egl_fill_attribs(drm, egl_attribs); - egl_attribs_ptr = &egl_attribs[0]; + const EGLint* attrib_ptr = NULL; + EGLint major; + EGLint minor; + EGLint n; + EGLint egl_attribs[16]; + EGLint* egl_attribs_ptr = NULL; + EGLint* attr = NULL; - if (!egl_create_context(&drm->egl, (attr != egl_attribs_ptr) - ? egl_attribs_ptr : NULL)) - { - INFO_LOG(VIDEO, "\n[EGL] Cannot create context error 0x%x",eglGetError()); - goto error; - } + attrib_ptr = egl_attribs_gles3; - if (!egl_create_surface(&drm->egl, (EGLNativeWindowType)drm->gbm_surface)) - { - INFO_LOG(VIDEO, "\n[EGL] Cannot create context error 0x%x",eglGetError()); - return false; - } + if (!egl_init_context(&drm->egl, EGL_PLATFORM_GBM_KHR, (EGLNativeDisplayType)drm->gbm_dev, &major, + &minor, &n, attrib_ptr, gbm_choose_xrgb8888_cb)) + { + INFO_LOG(VIDEO, "\n[EGL] Cannot init context error 0x%x", eglGetError()); + goto error; + } + attr = gfx_ctx_drm_egl_fill_attribs(drm, egl_attribs); + egl_attribs_ptr = &egl_attribs[0]; + + if (!egl_create_context(&drm->egl, (attr != egl_attribs_ptr) ? egl_attribs_ptr : NULL)) + { + INFO_LOG(VIDEO, "\n[EGL] Cannot create context error 0x%x", eglGetError()); + goto error; + } - egl_swap_buffers(&drm->egl); + if (!egl_create_surface(&drm->egl, (EGLNativeWindowType)drm->gbm_surface)) + { + INFO_LOG(VIDEO, "\n[EGL] Cannot create context error 0x%x", eglGetError()); + return false; + } - return true; + egl_swap_buffers(&drm->egl); + + return true; error: - return false; + return false; } -static bool gfx_ctx_drm_set_video_mode(void *data, - unsigned width, unsigned height, - bool fullscreen) +static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned height, bool fullscreen) { - int i, ret = 0; - struct drm_fb *fb = NULL; - gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; - float video_refresh_rate = (float)VideoInterface::GetTargetRefreshRate(); - - if (!drm) - return false; - - /* Find desired video mode, and use that. - * If not fullscreen, we get desired windowed size, - * which is not appropriate. */ - if ((width == 0 && height == 0) || !fullscreen) - g_drm_mode = &g_drm_connector->modes[0]; - else - { - /* Try to match refresh_rate as closely as possible. - * - * Lower resolutions tend to have multiple supported - * refresh rates as well. - */ - float minimum_fps_diff = 0.0f; - - /* Find best match. */ - for (i = 0; i < g_drm_connector->count_modes; i++) + int i, ret = 0; + struct drm_fb* fb = NULL; + gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)data; + float video_refresh_rate = (float)VideoInterface::GetTargetRefreshRate(); + + if (!drm) + return false; + + /* Find desired video mode, and use that. + * If not fullscreen, we get desired windowed size, + * which is not appropriate. */ + if ((width == 0 && height == 0) || !fullscreen) + g_drm_mode = &g_drm_connector->modes[0]; + else + { + /* Try to match refresh_rate as closely as possible. + * + * Lower resolutions tend to have multiple supported + * refresh rates as well. + */ + float minimum_fps_diff = 0.0f; + + /* Find best match. */ + for (i = 0; i < g_drm_connector->count_modes; i++) + { + float diff; + if (width != g_drm_connector->modes[i].hdisplay || + height != g_drm_connector->modes[i].vdisplay) + continue; + + diff = fabsf(g_drm_connector->modes[i].vrefresh - video_refresh_rate); + + if (!g_drm_mode || diff < minimum_fps_diff) { - float diff; - if (width != g_drm_connector->modes[i].hdisplay || - height != g_drm_connector->modes[i].vdisplay) - continue; - - diff = fabsf(g_drm_connector->modes[i].vrefresh - video_refresh_rate); - - if (!g_drm_mode || diff < minimum_fps_diff) - { - g_drm_mode = &g_drm_connector->modes[i]; - minimum_fps_diff = diff; - } + g_drm_mode = &g_drm_connector->modes[i]; + minimum_fps_diff = diff; } - } + } + } - if (!g_drm_mode) - { - INFO_LOG(VIDEO, "[KMS/EGL]: Did not find suitable video mode for %u x %u.\n", - width, height); - goto error; - } + if (!g_drm_mode) + { + INFO_LOG(VIDEO, "[KMS/EGL]: Did not find suitable video mode for %u x %u.\n", width, height); + goto error; + } - drm->fb_width = g_drm_mode->hdisplay; - drm->fb_height = g_drm_mode->vdisplay; + drm->fb_width = g_drm_mode->hdisplay; + drm->fb_height = g_drm_mode->vdisplay; - /* Create GBM surface. */ - drm->gbm_surface = gbm_surface_create( - drm->gbm_dev, - drm->fb_width, - drm->fb_height, - GBM_FORMAT_XRGB8888, - GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + /* Create GBM surface. */ + drm->gbm_surface = + gbm_surface_create(drm->gbm_dev, drm->fb_width, drm->fb_height, GBM_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - if (!drm->gbm_surface) - { - INFO_LOG(VIDEO, "[KMS/EGL]: Couldn't create GBM surface.\n"); - goto error; - } + if (!drm->gbm_surface) + { + INFO_LOG(VIDEO, "[KMS/EGL]: Couldn't create GBM surface.\n"); + goto error; + } - if (!gfx_ctx_drm_egl_set_video_mode(drm)) - { - INFO_LOG(VIDEO, "[KMS/EGL]: Couldn't set EGL video mode.\n"); - goto error; - } + if (!gfx_ctx_drm_egl_set_video_mode(drm)) + { + INFO_LOG(VIDEO, "[KMS/EGL]: Couldn't set EGL video mode.\n"); + goto error; + } - drm->bo = gbm_surface_lock_front_buffer(drm->gbm_surface); + drm->bo = gbm_surface_lock_front_buffer(drm->gbm_surface); - fb = (struct drm_fb*)gbm_bo_get_user_data(drm->bo); + fb = (struct drm_fb*)gbm_bo_get_user_data(drm->bo); - if (!fb) - fb = drm_fb_get_from_bo(drm->bo); + if (!fb) + fb = drm_fb_get_from_bo(drm->bo); - ret = drmModeSetCrtc(g_drm_fd, - g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode); - if (ret < 0) - { - INFO_LOG(VIDEO, "[KMS/EGL]: drmModeSetCrtc failed\n"); - goto error; - } - return true; + ret = drmModeSetCrtc(g_drm_fd, g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode); + if (ret < 0) + { + INFO_LOG(VIDEO, "[KMS/EGL]: drmModeSetCrtc failed\n"); + goto error; + } + return true; error: - gfx_ctx_drm_destroy_resources(drm); + gfx_ctx_drm_destroy_resources(drm); - if (drm) - free(drm); + if (drm) + free(drm); - return false; + return false; } -static void gfx_ctx_drm_destroy(void *data) +static void gfx_ctx_drm_destroy(void* data) { - gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)data; - if (!drm) - return; + if (!drm) + return; - gfx_ctx_drm_destroy_resources(drm); - free(drm); + gfx_ctx_drm_destroy_resources(drm); + free(drm); } - GLContextEGLDRM::~GLContextEGLDRM() { DestroyWindowSurface(); @@ -1136,12 +1103,12 @@ bool GLContextEGLDRM::IsHeadless() const void GLContextEGLDRM::Swap() { - gfx_ctx_drm_swap_buffers(g_drm); + gfx_ctx_drm_swap_buffers(g_drm); } void GLContextEGLDRM::SwapInterval(int interval) { - gfx_ctx_drm_swap_interval(g_drm, interval); - egl_set_swap_interval(m_egl, interval); + gfx_ctx_drm_swap_interval(g_drm, interval); + egl_set_swap_interval(m_egl, interval); } void* GLContextEGLDRM::GetFuncAddress(const std::string& name) @@ -1159,12 +1126,12 @@ bool GLContextEGLDRM::Initialize(const WindowSystemInfo& wsi, bool stereo, bool // Use current video mode, do not switch gfx_ctx_drm_set_video_mode(g_drm, 0, 0, false); - m_backbuffer_width = g_drm->fb_width; + m_backbuffer_width = g_drm->fb_width; m_backbuffer_height = g_drm->fb_height; m_egl = &g_drm->egl; m_opengl_mode = Mode::OpenGLES; - m_supports_surfaceless = check_egl_display_extension(m_egl,"EGL_KHR_surfaceless_context"); + m_supports_surfaceless = check_egl_display_extension(m_egl, "EGL_KHR_surfaceless_context"); eglBindAPI(EGL_OPENGL_ES_API); @@ -1179,11 +1146,12 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() eglBindAPI(EGL_OPENGL_ES_API); EGLint egl_attribs[16]; - EGLint *egl_attribs_ptr = NULL; - const EGLint *attrib_ptr = egl_attribs_gles3; + EGLint* egl_attribs_ptr = NULL; + const EGLint* attrib_ptr = egl_attribs_gles3; EGLint* attr = gfx_ctx_drm_egl_fill_attribs(g_drm, egl_attribs); egl_attribs_ptr = &egl_attribs[0]; - new_context->m_egl->ctx = eglCreateContext(m_egl->dpy, m_egl->config, m_egl->ctx, egl_attribs_ptr); + new_context->m_egl->ctx = + eglCreateContext(m_egl->dpy, m_egl->config, m_egl->ctx, egl_attribs_ptr); if (!new_context->m_egl->ctx) { ERROR_LOG(VIDEO, "\nError: eglCreateContext failed 0x%x\n", eglGetError()); @@ -1203,7 +1171,9 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() bool GLContextEGLDRM::CreateWindowSurface() { - EGLint attrib_list[] = { EGL_NONE, }; + EGLint attrib_list[] = { + EGL_NONE, + }; if (m_supports_surfaceless) { m_egl->surf = EGL_NO_SURFACE; @@ -1213,17 +1183,18 @@ bool GLContextEGLDRM::CreateWindowSurface() if (!IsHeadless()) { - if (!egl_create_surface(m_egl, (EGLNativeWindowType)g_drm->gbm_surface)) - { + if (!egl_create_surface(m_egl, (EGLNativeWindowType)g_drm->gbm_surface)) + { INFO_LOG(VIDEO, "\negl_create_surface failed, trying pbuffer failed 0x%x\n", eglGetError()); goto pbuffer; - } + } // Get dimensions from the surface. EGLint surface_width = 1, surface_height = 1; if (!eglQuerySurface(m_egl->dpy, m_egl->surf, EGL_WIDTH, &surface_width) || !eglQuerySurface(m_egl->dpy, m_egl->surf, EGL_HEIGHT, &surface_height)) { - INFO_LOG(VIDEO, "Failed to get surface dimensions via eglQuerySurface. Size may be incorrect."); + INFO_LOG(VIDEO, + "Failed to get surface dimensions via eglQuerySurface. Size may be incorrect."); } m_backbuffer_width = static_cast(surface_width); m_backbuffer_height = static_cast(surface_height); @@ -1231,13 +1202,13 @@ bool GLContextEGLDRM::CreateWindowSurface() } pbuffer: - m_egl->surf = eglCreatePbufferSurface(m_egl->dpy, m_egl->config, attrib_list); - if (!m_egl->surf) - { - INFO_LOG(VIDEO, "\nError: eglCreatePbufferSurface failed 0x%x\n", eglGetError()); - return false; - } - return true; + m_egl->surf = eglCreatePbufferSurface(m_egl->dpy, m_egl->config, attrib_list); + if (!m_egl->surf) + { + INFO_LOG(VIDEO, "\nError: eglCreatePbufferSurface failed 0x%x\n", eglGetError()); + return false; + } + return true; } void GLContextEGLDRM::DestroyWindowSurface() @@ -1273,7 +1244,7 @@ bool GLContextEGLDRM::ClearCurrent() // Close backend void GLContextEGLDRM::DestroyContext() { -if (!m_egl->ctx) + if (!m_egl->ctx) return; if (eglGetCurrentContext() == m_egl->ctx) From 414cb0ec131cad6667f229c7b5b8b16969d42772 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 16:04:56 +0200 Subject: [PATCH 11/26] Indent properly Source/Core/Common/CMakeLists.txt --- Source/Core/Common/CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 6e220d9047bf..6e7574b7c8d6 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -226,16 +226,16 @@ if(ENABLE_EGL AND EGL_FOUND) find_package(Libgbm) if (LIBDRM_FOUND AND LIBGBM_FOUND) target_sources(common PRIVATE - GL/GLInterface/EGL.cpp - GL/GLInterface/EGL.h - GL/GLInterface/EGLDRM.cpp - GL/GLInterface/EGLDRM.h + GL/GLInterface/EGL.cpp + GL/GLInterface/EGL.h + GL/GLInterface/EGLDRM.cpp + GL/GLInterface/EGLDRM.h ) else() - target_sources(common PRIVATE - GL/GLInterface/EGL.cpp - GL/GLInterface/EGL.h - ) + target_sources(common PRIVATE + GL/GLInterface/EGL.cpp + GL/GLInterface/EGL.h + ) endif() if(ANDROID) target_sources(common PRIVATE From c55dc590e461bc7e9d647ad0cb8e0d7ff50044ae Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 16:08:56 +0200 Subject: [PATCH 12/26] Fix headers order / C++ compliance and move to EGLContextData struct --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 45 ++++++++++---------- Source/Core/Common/GL/GLInterface/EGLDRM.h | 6 +-- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index 100e60d1c78e..ff1b13967cd1 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -19,26 +19,27 @@ * If not, see . */ -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include -#include #include #include -#include -#include -#include #include #include #include #include -#include -#include -#include #include #include -#include -#include #include #include @@ -80,7 +81,7 @@ using EGLAcceptConfigCB = bool (*)(void* display_data, EGLDisplay dpy, EGLConfig typedef struct gfx_ctx_drm_data { - egl_ctx_data_t egl; + EGLContextData egl; int fd; int interval; unsigned fb_width; @@ -126,7 +127,7 @@ void drm_free(void); bool drm_get_connector(int fd); float drm_get_refresh_rate(void* data); -static void egl_destroy(egl_ctx_data_t* egl) +static void egl_destroy(EGLContextData* egl) { if (egl->dpy) { @@ -151,14 +152,14 @@ static void egl_destroy(egl_ctx_data_t* egl) static void egl_swap_buffers(void* data) { - egl_ctx_data_t* egl = (egl_ctx_data_t*)data; + EGLContextData* egl = (EGLContextData*)data; if (egl && egl->dpy != EGL_NO_DISPLAY && egl->surf != EGL_NO_SURFACE) { eglSwapBuffers(egl->dpy, egl->surf); } } -static void egl_set_swap_interval(egl_ctx_data_t* egl, int interval) +static void egl_set_swap_interval(EGLContextData* egl, int interval) { /* Can be called before initialization. * Some contexts require that swap interval @@ -230,7 +231,7 @@ static bool check_egl_client_extension(const char* name) static bool check_egl_display_extension(void* data, const char* name) { size_t nameLen; - egl_ctx_data_t* egl = (egl_ctx_data_t*)data; + EGLContextData* egl = (EGLContextData*)data; if (!egl || egl->dpy == EGL_NO_DISPLAY) return false; @@ -308,7 +309,7 @@ static EGLDisplay get_egl_display(EGLenum platform, void* native) return eglGetDisplay((EGLNativeDisplayType)native); } -static bool egl_get_native_visual_id(egl_ctx_data_t* egl, EGLint* value) +static bool egl_get_native_visual_id(EGLContextData* egl, EGLint* value) { if (!eglGetConfigAttrib(egl->dpy, egl->config, EGL_NATIVE_VISUAL_ID, value)) { @@ -319,7 +320,7 @@ static bool egl_get_native_visual_id(egl_ctx_data_t* egl, EGLint* value) return true; } -static bool egl_init_context_common(egl_ctx_data_t* egl, EGLint* count, const EGLint* attrib_ptr, +static bool egl_init_context_common(EGLContextData* egl, EGLint* count, const EGLint* attrib_ptr, egl_accept_config_cb_t cb, void* display_data) { EGLint i; @@ -364,7 +365,7 @@ static bool egl_init_context_common(egl_ctx_data_t* egl, EGLint* count, const EG return true; } -static bool egl_init_context(egl_ctx_data_t* egl, EGLenum platform, void* display_data, +static bool egl_init_context(EGLContextData* egl, EGLenum platform, void* display_data, EGLint* major, EGLint* minor, EGLint* count, const EGLint* attrib_ptr, egl_accept_config_cb_t cb) { @@ -386,7 +387,7 @@ static bool egl_init_context(egl_ctx_data_t* egl, EGLenum platform, void* displa return egl_init_context_common(egl, count, attrib_ptr, cb, display_data); } -static bool egl_create_context(egl_ctx_data_t* egl, const EGLint* egl_attribs) +static bool egl_create_context(EGLContextData* egl, const EGLint* egl_attribs) { EGLContext ctx = eglCreateContext(egl->dpy, egl->config, EGL_NO_CONTEXT, egl_attribs); @@ -398,7 +399,7 @@ static bool egl_create_context(egl_ctx_data_t* egl, const EGLint* egl_attribs) return true; } -static bool egl_create_surface(egl_ctx_data_t* egl, void* native_window) +static bool egl_create_surface(EGLContextData* egl, void* native_window) { EGLint window_attribs[] = { EGL_RENDER_BUFFER, @@ -1141,8 +1142,8 @@ bool GLContextEGLDRM::Initialize(const WindowSystemInfo& wsi, bool stereo, bool std::unique_ptr GLContextEGLDRM::CreateSharedContext() { std::unique_ptr new_context = std::make_unique(); - new_context->m_egl = (egl_ctx_data_t*)malloc(sizeof(egl_ctx_data_t)); - memcpy(new_context->m_egl, m_egl, sizeof(egl_ctx_data_t)); + new_context->m_egl = (EGLContextData*)malloc(sizeof(EGLContextData)); + memcpy(new_context->m_egl, m_egl, sizeof(EGLContextData)); eglBindAPI(EGL_OPENGL_ES_API); EGLint egl_attribs[16]; diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.h b/Source/Core/Common/GL/GLInterface/EGLDRM.h index 9b38f00900cd..46d361a3a148 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.h +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.h @@ -11,7 +11,7 @@ #include "Common/GL/GLContext.h" -typedef struct +struct EGLContextData { EGLContext ctx; EGLSurface surf; @@ -22,7 +22,7 @@ typedef struct unsigned major; unsigned minor; -} egl_ctx_data_t; +}; class GLContextEGLDRM : public GLContext { @@ -51,5 +51,5 @@ class GLContextEGLDRM : public GLContext void DestroyContext(); bool m_supports_surfaceless = false; - egl_ctx_data_t* m_egl; + EGLContextData* m_egl; }; From 02575c2cbfa074043668d7d3b41b0bd122e9e664 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 16:11:49 +0200 Subject: [PATCH 13/26] Move gfx_ctx_drm_data_t to GFXContextDRMData --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 30 ++++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index ff1b13967cd1..f252fb091701 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -79,7 +79,7 @@ using EGLAcceptConfigCB = bool (*)(void* display_data, EGLDisplay dpy, EGLConfig config); -typedef struct gfx_ctx_drm_data +struct GFXContextDRMData { EGLContextData egl; int fd; @@ -93,7 +93,7 @@ typedef struct gfx_ctx_drm_data struct gbm_bo* next_bo; struct gbm_surface* gbm_surface; struct gbm_device* gbm_dev; -} gfx_ctx_drm_data_t; +}; struct drm_fb { @@ -634,7 +634,7 @@ static struct drm_fb* drm_fb_get_from_bo(struct gbm_bo* bo) static void gfx_ctx_drm_swap_interval(void* data, int interval) { - gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)data; + GFXContextDRMData* drm = (GFXContextDRMData*)data; drm->interval = interval; if (interval > 1) @@ -665,7 +665,7 @@ static void drm_flip_handler(int fd, unsigned frame, unsigned sec, unsigned usec *(bool*)data = false; } -static bool gfx_ctx_drm_wait_flip(gfx_ctx_drm_data_t* drm, bool block) +static bool gfx_ctx_drm_wait_flip(GFXContextDRMData* drm, bool block) { int timeout = 0; @@ -696,7 +696,7 @@ static bool gfx_ctx_drm_wait_flip(gfx_ctx_drm_data_t* drm, bool block) return false; } -static bool gfx_ctx_drm_queue_flip(gfx_ctx_drm_data_t* drm) +static bool gfx_ctx_drm_queue_flip(GFXContextDRMData* drm) { struct drm_fb* fb = NULL; @@ -717,7 +717,7 @@ static bool gfx_ctx_drm_queue_flip(gfx_ctx_drm_data_t* drm) static void gfx_ctx_drm_swap_buffers(void* data) { - gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)data; + GFXContextDRMData* drm = (GFXContextDRMData*)data; unsigned max_swapchain_images = 2; // settings->uints.video_max_swapchain_images; egl_swap_buffers(&drm->egl); @@ -744,7 +744,7 @@ static void gfx_ctx_drm_swap_buffers(void* data) static void gfx_ctx_drm_get_video_size(void* data, unsigned* width, unsigned* height) { - gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)data; + GFXContextDRMData* drm = (GFXContextDRMData*)data; if (!drm) { @@ -756,7 +756,7 @@ static void gfx_ctx_drm_get_video_size(void* data, unsigned* width, unsigned* he *height = drm->fb_height; } -static void free_drm_resources(gfx_ctx_drm_data_t* drm) +static void free_drm_resources(GFXContextDRMData* drm) { if (!drm) return; @@ -786,7 +786,7 @@ static void free_drm_resources(gfx_ctx_drm_data_t* drm) g_drm_fd = -1; } -static void gfx_ctx_drm_destroy_resources(gfx_ctx_drm_data_t* drm) +static void gfx_ctx_drm_destroy_resources(GFXContextDRMData* drm) { if (!drm) return; @@ -815,7 +815,7 @@ static void* gfx_ctx_drm_init() unsigned monitor_index; unsigned gpu_index = 0; const char* gpu = NULL; - gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)calloc(1, sizeof(gfx_ctx_drm_data_t)); + GFXContextDRMData* drm = (GFXContextDRMData*)calloc(1, sizeof(GFXContextDRMData)); if (!drm) return NULL; @@ -895,7 +895,7 @@ static void* gfx_ctx_drm_init() return NULL; } -static EGLint* gfx_ctx_drm_egl_fill_attribs(gfx_ctx_drm_data_t* drm, EGLint* attr) +static EGLint* gfx_ctx_drm_egl_fill_attribs(GFXContextDRMData* drm, EGLint* attr) { *attr++ = EGL_CONTEXT_CLIENT_VERSION; *attr++ = drm->egl.major ? (EGLint)drm->egl.major : 2; @@ -946,7 +946,7 @@ static const EGLint egl_attribs_gles3[] = { }; #endif -static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t* drm) +static bool gfx_ctx_drm_egl_set_video_mode(GFXContextDRMData* drm) { const EGLint* attrib_ptr = NULL; EGLint major; @@ -991,7 +991,7 @@ static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned heig { int i, ret = 0; struct drm_fb* fb = NULL; - gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)data; + GFXContextDRMData* drm = (GFXContextDRMData*)data; float video_refresh_rate = (float)VideoInterface::GetTargetRefreshRate(); if (!drm) @@ -1081,7 +1081,7 @@ static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned heig static void gfx_ctx_drm_destroy(void* data) { - gfx_ctx_drm_data_t* drm = (gfx_ctx_drm_data_t*)data; + GFXContextDRMData* drm = (GFXContextDRMData*)data; if (!drm) return; @@ -1121,7 +1121,7 @@ void* GLContextEGLDRM::GetFuncAddress(const std::string& name) // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() bool GLContextEGLDRM::Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) { - g_drm = (gfx_ctx_drm_data_t*)gfx_ctx_drm_init(); + g_drm = (GFXContextDRMData*)gfx_ctx_drm_init(); eglBindAPI(EGL_OPENGL_ES_API); From 67cb42244209095b64022b3616000c7686859655 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 16:15:39 +0200 Subject: [PATCH 14/26] Remove useless "private:" declaration in PlatformDRM.cpp --- Source/Core/DolphinNoGUI/PlatformDRM.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/Core/DolphinNoGUI/PlatformDRM.cpp b/Source/Core/DolphinNoGUI/PlatformDRM.cpp index 255888ad4cc1..6e4dc08eedf2 100644 --- a/Source/Core/DolphinNoGUI/PlatformDRM.cpp +++ b/Source/Core/DolphinNoGUI/PlatformDRM.cpp @@ -36,8 +36,6 @@ class PlatformDRM : public Platform void MainLoop() override; WindowSystemInfo GetWindowSystemInfo() const override; - -private: }; PlatformDRM::~PlatformDRM() = default; From dcabf7a330cfeb8db857ceced4e40034b3731877 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 16:17:41 +0200 Subject: [PATCH 15/26] Harmonize NULL to nullptr in EGLDRM.cpp --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 64 ++++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index f252fb091701..799921270069 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -107,15 +107,15 @@ static struct pollfd g_drm_fds; static uint32_t g_connector_id = 0; static int g_drm_fd = 0; static uint32_t g_crtc_id = 0; -static drmModeCrtc* g_orig_crtc = NULL; -static drmModeConnector* g_drm_connector = NULL; -static drmModeModeInfo* g_drm_mode = NULL; +static drmModeCrtc* g_orig_crtc = nullptr; +static drmModeConnector* g_drm_connector = nullptr; +static drmModeModeInfo* g_drm_mode = nullptr; /* TODO/FIXME - static globals */ -static drmModeRes* g_drm_resources = NULL; -static drmModeEncoder* g_drm_encoder = NULL; +static drmModeRes* g_drm_resources = nullptr; +static drmModeEncoder* g_drm_encoder = nullptr; -static gfx_ctx_drm_data* g_drm = NULL; +static gfx_ctx_drm_data* g_drm = nullptr; bool drm_get_encoder(int fd); @@ -276,7 +276,7 @@ static EGLDisplay get_egl_display(EGLenum platform, void* native) if (ptr_eglGetPlatformDisplay) { - EGLDisplay dpy = ptr_eglGetPlatformDisplay(platform, native, NULL); + EGLDisplay dpy = ptr_eglGetPlatformDisplay(platform, native, nullptr); if (dpy != EGL_NO_DISPLAY) return dpy; } @@ -294,7 +294,7 @@ static EGLDisplay get_egl_display(EGLenum platform, void* native) if (ptr_eglGetPlatformDisplayEXT) { - EGLDisplay dpy = ptr_eglGetPlatformDisplayEXT(platform, native, NULL); + EGLDisplay dpy = ptr_eglGetPlatformDisplayEXT(platform, native, nullptr); if (dpy != EGL_NO_DISPLAY) return dpy; } @@ -325,11 +325,11 @@ static bool egl_init_context_common(EGLContextData* egl, EGLint* count, const EG { EGLint i; EGLint matched = 0; - EGLConfig* configs = NULL; + EGLConfig* configs = nullptr; if (!egl) return false; - if (!eglGetConfigs(egl->dpy, NULL, 0, count) || *count < 1) + if (!eglGetConfigs(egl->dpy, nullptr, 0, count) || *count < 1) { INFO_LOG(VIDEO, "[EGL]: No configs to choose from.\n"); return false; @@ -451,7 +451,7 @@ void drm_restore_crtc(void) g_orig_crtc->y, &g_connector_id, 1, &g_orig_crtc->mode); drmModeFreeCrtc(g_orig_crtc); - g_orig_crtc = NULL; + g_orig_crtc = nullptr; } bool drm_get_resources(int fd) @@ -511,7 +511,7 @@ bool drm_get_connector(int fd) } drmModeFreeConnector(g_drm_connector); - g_drm_connector = NULL; + g_drm_connector = nullptr; } if (!g_drm_connector) @@ -537,7 +537,7 @@ bool drm_get_encoder(int fd) break; drmModeFreeEncoder(g_drm_encoder); - g_drm_encoder = NULL; + g_drm_encoder = nullptr; } if (!g_drm_encoder) @@ -589,9 +589,9 @@ void drm_free(void) memset(&g_drm_fds, 0, sizeof(struct pollfd)); memset(&g_drm_evctx, 0, sizeof(drmEventContext)); - g_drm_encoder = NULL; - g_drm_connector = NULL; - g_drm_resources = NULL; + g_drm_encoder = nullptr; + g_drm_connector = nullptr; + g_drm_resources = nullptr; } static void drm_fb_destroy_callback(struct gbm_bo* bo, void* data) @@ -629,7 +629,7 @@ static struct drm_fb* drm_fb_get_from_bo(struct gbm_bo* bo) error: INFO_LOG(VIDEO, "[KMS]: Failed to create FB: %s\n", strerror(errno)); free(fb); - return NULL; + return nullptr; } static void gfx_ctx_drm_swap_interval(void* data, int interval) @@ -698,7 +698,7 @@ static bool gfx_ctx_drm_wait_flip(GFXContextDRMData* drm, bool block) static bool gfx_ctx_drm_queue_flip(GFXContextDRMData* drm) { - struct drm_fb* fb = NULL; + struct drm_fb* fb = nullptr; drm->next_bo = gbm_surface_lock_front_buffer(drm->gbm_surface); fb = (struct drm_fb*)gbm_bo_get_user_data(drm->next_bo); @@ -781,8 +781,8 @@ static void free_drm_resources(GFXContextDRMData* drm) } } - drm->gbm_surface = NULL; - drm->gbm_dev = NULL; + drm->gbm_surface = nullptr; + drm->gbm_dev = nullptr; g_drm_fd = -1; } @@ -798,15 +798,15 @@ static void gfx_ctx_drm_destroy_resources(GFXContextDRMData* drm) free_drm_resources(drm); - g_drm_mode = NULL; + g_drm_mode = nullptr; g_crtc_id = 0; g_connector_id = 0; drm->fb_width = 0; drm->fb_height = 0; - drm->bo = NULL; - drm->next_bo = NULL; + drm->bo = nullptr; + drm->next_bo = nullptr; } static void* gfx_ctx_drm_init() @@ -814,11 +814,11 @@ static void* gfx_ctx_drm_init() int fd, i; unsigned monitor_index; unsigned gpu_index = 0; - const char* gpu = NULL; + const char* gpu = nullptr; GFXContextDRMData* drm = (GFXContextDRMData*)calloc(1, sizeof(GFXContextDRMData)); if (!drm) - return NULL; + return nullptr; drm->fd = -1; free_drm_resources(drm); @@ -892,7 +892,7 @@ static void* gfx_ctx_drm_init() if (drm) free(drm); - return NULL; + return nullptr; } static EGLint* gfx_ctx_drm_egl_fill_attribs(GFXContextDRMData* drm, EGLint* attr) @@ -948,13 +948,13 @@ static const EGLint egl_attribs_gles3[] = { static bool gfx_ctx_drm_egl_set_video_mode(GFXContextDRMData* drm) { - const EGLint* attrib_ptr = NULL; + const EGLint* attrib_ptr = nullptr; EGLint major; EGLint minor; EGLint n; EGLint egl_attribs[16]; - EGLint* egl_attribs_ptr = NULL; - EGLint* attr = NULL; + EGLint* egl_attribs_ptr = nullptr; + EGLint* attr = nullptr; attrib_ptr = egl_attribs_gles3; @@ -967,7 +967,7 @@ static bool gfx_ctx_drm_egl_set_video_mode(GFXContextDRMData* drm) attr = gfx_ctx_drm_egl_fill_attribs(drm, egl_attribs); egl_attribs_ptr = &egl_attribs[0]; - if (!egl_create_context(&drm->egl, (attr != egl_attribs_ptr) ? egl_attribs_ptr : NULL)) + if (!egl_create_context(&drm->egl, (attr != egl_attribs_ptr) ? egl_attribs_ptr : nullptr)) { INFO_LOG(VIDEO, "\n[EGL] Cannot create context error 0x%x", eglGetError()); goto error; @@ -990,7 +990,7 @@ static bool gfx_ctx_drm_egl_set_video_mode(GFXContextDRMData* drm) static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned height, bool fullscreen) { int i, ret = 0; - struct drm_fb* fb = NULL; + struct drm_fb* fb = nullptr; GFXContextDRMData* drm = (GFXContextDRMData*)data; float video_refresh_rate = (float)VideoInterface::GetTargetRefreshRate(); @@ -1147,7 +1147,7 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() eglBindAPI(EGL_OPENGL_ES_API); EGLint egl_attribs[16]; - EGLint* egl_attribs_ptr = NULL; + EGLint* egl_attribs_ptr = nullptr; const EGLint* attrib_ptr = egl_attribs_gles3; EGLint* attr = gfx_ctx_drm_egl_fill_attribs(g_drm, egl_attribs); egl_attribs_ptr = &egl_attribs[0]; From 810f2240390b6f55314c319a2917bafe498d8ba4 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 16:28:31 +0200 Subject: [PATCH 16/26] Fix build following PR changes --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 6 +++--- Source/Core/DolphinNoGUI/PlatformDRM.cpp | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index 799921270069..ec5113d5660e 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -115,7 +115,7 @@ static drmModeModeInfo* g_drm_mode = nullptr; static drmModeRes* g_drm_resources = nullptr; static drmModeEncoder* g_drm_encoder = nullptr; -static gfx_ctx_drm_data* g_drm = nullptr; +static GFXContextDRMData* g_drm = nullptr; bool drm_get_encoder(int fd); @@ -321,7 +321,7 @@ static bool egl_get_native_visual_id(EGLContextData* egl, EGLint* value) } static bool egl_init_context_common(EGLContextData* egl, EGLint* count, const EGLint* attrib_ptr, - egl_accept_config_cb_t cb, void* display_data) + EGLAcceptConfigCB cb, void* display_data) { EGLint i; EGLint matched = 0; @@ -367,7 +367,7 @@ static bool egl_init_context_common(EGLContextData* egl, EGLint* count, const EG static bool egl_init_context(EGLContextData* egl, EGLenum platform, void* display_data, EGLint* major, EGLint* minor, EGLint* count, const EGLint* attrib_ptr, - egl_accept_config_cb_t cb) + EGLAcceptConfigCB cb) { EGLDisplay dpy = get_egl_display(platform, display_data); diff --git a/Source/Core/DolphinNoGUI/PlatformDRM.cpp b/Source/Core/DolphinNoGUI/PlatformDRM.cpp index 6e4dc08eedf2..b210cea1599f 100644 --- a/Source/Core/DolphinNoGUI/PlatformDRM.cpp +++ b/Source/Core/DolphinNoGUI/PlatformDRM.cpp @@ -39,8 +39,6 @@ class PlatformDRM : public Platform }; PlatformDRM::~PlatformDRM() = default; -{ -} bool PlatformDRM::Init() { From c72d6fede67631ebba59bb28c5f9ad495474b676 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 16:36:44 +0200 Subject: [PATCH 17/26] Fix warnings and unused stuff --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 41 +------------------- 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index ec5113d5660e..0414072170c6 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -309,17 +309,6 @@ static EGLDisplay get_egl_display(EGLenum platform, void* native) return eglGetDisplay((EGLNativeDisplayType)native); } -static bool egl_get_native_visual_id(EGLContextData* egl, EGLint* value) -{ - if (!eglGetConfigAttrib(egl->dpy, egl->config, EGL_NATIVE_VISUAL_ID, value)) - { - INFO_LOG(VIDEO, "[EGL]: egl_get_native_visual_id failed.\n"); - return false; - } - - return true; -} - static bool egl_init_context_common(EGLContextData* egl, EGLint* count, const EGLint* attrib_ptr, EGLAcceptConfigCB cb, void* display_data) { @@ -742,20 +731,6 @@ static void gfx_ctx_drm_swap_buffers(void* data) gfx_ctx_drm_wait_flip(drm, true); } -static void gfx_ctx_drm_get_video_size(void* data, unsigned* width, unsigned* height) -{ - GFXContextDRMData* drm = (GFXContextDRMData*)data; - - if (!drm) - { - INFO_LOG(VIDEO, "\nCannot get drm video size\n"); - return; - } - - *width = drm->fb_width; - *height = drm->fb_height; -} - static void free_drm_resources(GFXContextDRMData* drm) { if (!drm) @@ -811,10 +786,7 @@ static void gfx_ctx_drm_destroy_resources(GFXContextDRMData* drm) static void* gfx_ctx_drm_init() { - int fd, i; - unsigned monitor_index; - unsigned gpu_index = 0; - const char* gpu = nullptr; + int fd; GFXContextDRMData* drm = (GFXContextDRMData*)calloc(1, sizeof(GFXContextDRMData)); if (!drm) @@ -885,14 +857,6 @@ static void* gfx_ctx_drm_init() g_drm_fd = fd; return drm; - -error: - gfx_ctx_drm_destroy_resources(drm); - - if (drm) - free(drm); - - return nullptr; } static EGLint* gfx_ctx_drm_egl_fill_attribs(GFXContextDRMData* drm, EGLint* attr) @@ -1148,8 +1112,7 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() eglBindAPI(EGL_OPENGL_ES_API); EGLint egl_attribs[16]; EGLint* egl_attribs_ptr = nullptr; - const EGLint* attrib_ptr = egl_attribs_gles3; - EGLint* attr = gfx_ctx_drm_egl_fill_attribs(g_drm, egl_attribs); + gfx_ctx_drm_egl_fill_attribs(g_drm, egl_attribs); egl_attribs_ptr = &egl_attribs[0]; new_context->m_egl->ctx = eglCreateContext(m_egl->dpy, m_egl->config, m_egl->ctx, egl_attribs_ptr); From de60407f2f907d174079b162a178bcb94b18d6d6 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 16:49:51 +0200 Subject: [PATCH 18/26] Refactor #1 --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 100 ++++++++----------- 1 file changed, 41 insertions(+), 59 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index 0414072170c6..8bf87db2270d 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -123,7 +123,6 @@ bool drm_get_encoder(int fd); void drm_restore_crtc(void); bool drm_get_resources(int fd); void drm_setup(int fd); -void drm_free(void); bool drm_get_connector(int fd); float drm_get_refresh_rate(void* data); @@ -566,23 +565,6 @@ float drm_get_refresh_rate(void* data) return refresh_rate; } -void drm_free(void) -{ - if (g_drm_encoder) - drmModeFreeEncoder(g_drm_encoder); - if (g_drm_connector) - drmModeFreeConnector(g_drm_connector); - if (g_drm_resources) - drmModeFreeResources(g_drm_resources); - - memset(&g_drm_fds, 0, sizeof(struct pollfd)); - memset(&g_drm_evctx, 0, sizeof(drmEventContext)); - - g_drm_encoder = nullptr; - g_drm_connector = nullptr; - g_drm_resources = nullptr; -} - static void drm_fb_destroy_callback(struct gbm_bo* bo, void* data) { struct drm_fb* fb = (struct drm_fb*)data; @@ -704,33 +686,6 @@ static bool gfx_ctx_drm_queue_flip(GFXContextDRMData* drm) return false; } -static void gfx_ctx_drm_swap_buffers(void* data) -{ - GFXContextDRMData* drm = (GFXContextDRMData*)data; - unsigned max_swapchain_images = 2; // settings->uints.video_max_swapchain_images; - - egl_swap_buffers(&drm->egl); - - /* I guess we have to wait for flip to have taken - * place before another flip can be queued up. - * - * If true, we are still waiting for a flip - * (nonblocking mode, so just drop the frame). */ - if (gfx_ctx_drm_wait_flip(drm, drm->interval)) - { - INFO_LOG(VIDEO, "\nwait flip"); - return; - } - - drm->waiting_for_flip = gfx_ctx_drm_queue_flip(drm); - - /* Triple-buffered page flips */ - if (max_swapchain_images >= 3 && gbm_surface_has_free_buffers(drm->gbm_surface)) - return; - - gfx_ctx_drm_wait_flip(drm, true); -} - static void free_drm_resources(GFXContextDRMData* drm) { if (!drm) @@ -745,7 +700,19 @@ static void free_drm_resources(GFXContextDRMData* drm) if (drm->gbm_dev) gbm_device_destroy(drm->gbm_dev); - drm_free(); + if (g_drm_encoder) + drmModeFreeEncoder(g_drm_encoder); + if (g_drm_connector) + drmModeFreeConnector(g_drm_connector); + if (g_drm_resources) + drmModeFreeResources(g_drm_resources); + + memset(&g_drm_fds, 0, sizeof(struct pollfd)); + memset(&g_drm_evctx, 0, sizeof(drmEventContext)); + + g_drm_encoder = nullptr; + g_drm_connector = nullptr; + g_drm_resources = nullptr; if (drm->fd >= 0) { @@ -1043,22 +1010,16 @@ static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned heig return false; } -static void gfx_ctx_drm_destroy(void* data) -{ - GFXContextDRMData* drm = (GFXContextDRMData*)data; - - if (!drm) - return; - - gfx_ctx_drm_destroy_resources(drm); - free(drm); -} - GLContextEGLDRM::~GLContextEGLDRM() { DestroyWindowSurface(); DestroyContext(); - gfx_ctx_drm_destroy(g_drm); + + if (!g_drm) + return; + + gfx_ctx_drm_destroy_resources(g_drm); + free(g_drm); } bool GLContextEGLDRM::IsHeadless() const @@ -1068,7 +1029,28 @@ bool GLContextEGLDRM::IsHeadless() const void GLContextEGLDRM::Swap() { - gfx_ctx_drm_swap_buffers(g_drm); + unsigned max_swapchain_images = 2; // double-buffering + + egl_swap_buffers(&g_drm->egl); + + /* I guess we have to wait for flip to have taken + * place before another flip can be queued up. + * + * If true, we are still waiting for a flip + * (nonblocking mode, so just drop the frame). */ + if (gfx_ctx_drm_wait_flip(g_drm, g_drm->interval)) + { + INFO_LOG(VIDEO, "\nwait flip"); + return; + } + + g_drm->waiting_for_flip = gfx_ctx_drm_queue_flip(g_drm); + + /* Triple-buffered page flips */ + if (max_swapchain_images >= 3 && gbm_surface_has_free_buffers(g_drm->gbm_surface)) + return; + + gfx_ctx_drm_wait_flip(g_drm, true); } void GLContextEGLDRM::SwapInterval(int interval) { From 32ac53b784fb38b60bb6d38f62e5065499ca815f Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 18:47:07 +0200 Subject: [PATCH 19/26] Refactor (2) --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 258 +++++++------------ 1 file changed, 96 insertions(+), 162 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index 8bf87db2270d..14c7f45b7b16 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -67,14 +67,6 @@ #define EGL_KHR_create_context 1 #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB -#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD -#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD -#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE -#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF -#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 -#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 -#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 -#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 #endif /* EGL_KHR_create_context */ using EGLAcceptConfigCB = bool (*)(void* display_data, EGLDisplay dpy, EGLConfig config); @@ -87,12 +79,23 @@ struct GFXContextDRMData unsigned fb_width; unsigned fb_height; - bool core_hw_context_enable; bool waiting_for_flip; struct gbm_bo* bo; struct gbm_bo* next_bo; struct gbm_surface* gbm_surface; struct gbm_device* gbm_dev; + + drmEventContext drm_evctx; + struct pollfd drm_fds; + uint32_t connector_id = 0; + int drm_fd = 0; + uint32_t crtc_id = 0; + drmModeCrtc* orig_crtc = nullptr; + drmModeConnector* drm_connector = nullptr; + drmModeModeInfo* drm_mode = nullptr; + + drmModeRes* drm_resources = nullptr; + drmModeEncoder* drm_encoder = nullptr; }; struct drm_fb @@ -101,30 +104,13 @@ struct drm_fb uint32_t fb_id; }; -/* TODO/FIXME - globals */ -static drmEventContext g_drm_evctx; -static struct pollfd g_drm_fds; -static uint32_t g_connector_id = 0; -static int g_drm_fd = 0; -static uint32_t g_crtc_id = 0; -static drmModeCrtc* g_orig_crtc = nullptr; -static drmModeConnector* g_drm_connector = nullptr; -static drmModeModeInfo* g_drm_mode = nullptr; - /* TODO/FIXME - static globals */ -static drmModeRes* g_drm_resources = nullptr; -static drmModeEncoder* g_drm_encoder = nullptr; - static GFXContextDRMData* g_drm = nullptr; bool drm_get_encoder(int fd); /* Restore the original CRTC. */ -void drm_restore_crtc(void); -bool drm_get_resources(int fd); -void drm_setup(int fd); bool drm_get_connector(int fd); -float drm_get_refresh_rate(void* data); static void egl_destroy(EGLContextData* egl) { @@ -412,48 +398,23 @@ static bool egl_create_surface(EGLContextData* egl, void* native_window) static bool drm_wait_flip(int timeout) { - g_drm_fds.revents = 0; + g_drm->drm_fds.revents = 0; - if (poll(&g_drm_fds, 1, timeout) < 0) + if (poll(&g_drm->drm_fds, 1, timeout) < 0) return false; - if (g_drm_fds.revents & (POLLHUP | POLLERR)) + if (g_drm->drm_fds.revents & (POLLHUP | POLLERR)) return false; - if (g_drm_fds.revents & POLLIN) + if (g_drm->drm_fds.revents & POLLIN) { - drmHandleEvent(g_drm_fd, &g_drm_evctx); + drmHandleEvent(g_drm->drm_fd, &g_drm->drm_evctx); return true; } return false; } -/* Restore the original CRTC. */ -void drm_restore_crtc(void) -{ - if (!g_orig_crtc) - return; - - drmModeSetCrtc(g_drm_fd, g_orig_crtc->crtc_id, g_orig_crtc->buffer_id, g_orig_crtc->x, - g_orig_crtc->y, &g_connector_id, 1, &g_orig_crtc->mode); - - drmModeFreeCrtc(g_orig_crtc); - g_orig_crtc = nullptr; -} - -bool drm_get_resources(int fd) -{ - g_drm_resources = drmModeGetResources(fd); - if (!g_drm_resources) - { - INFO_LOG(VIDEO, "[DRM]: Couldn't get device resources.\n"); - return false; - } - - return true; -} - bool drm_get_connector(int fd) { unsigned i; @@ -462,11 +423,11 @@ bool drm_get_connector(int fd) /* Enumerate all connectors. */ - INFO_LOG(VIDEO, "[DRM]: Found %d connectors.\n", g_drm_resources->count_connectors); + INFO_LOG(VIDEO, "[DRM]: Found %d connectors.\n", g_drm->drm_resources->count_connectors); - for (i = 0; (int)i < g_drm_resources->count_connectors; i++) + for (i = 0; (int)i < g_drm->drm_resources->count_connectors; i++) { - drmModeConnectorPtr conn = drmModeGetConnector(fd, g_drm_resources->connectors[i]); + drmModeConnectorPtr conn = drmModeGetConnector(fd, g_drm->drm_resources->connectors[i]); if (conn) { @@ -485,24 +446,24 @@ bool drm_get_connector(int fd) monitor_index_count = 0; - for (i = 0; (int)i < g_drm_resources->count_connectors; i++) + for (i = 0; (int)i < g_drm->drm_resources->count_connectors; i++) { - g_drm_connector = drmModeGetConnector(fd, g_drm_resources->connectors[i]); + g_drm->drm_connector = drmModeGetConnector(fd, g_drm->drm_resources->connectors[i]); - if (!g_drm_connector) + if (!g_drm->drm_connector) continue; - if (g_drm_connector->connection == DRM_MODE_CONNECTED && g_drm_connector->count_modes > 0) + if (g_drm->drm_connector->connection == DRM_MODE_CONNECTED && g_drm->drm_connector->count_modes > 0) { monitor_index_count++; if (monitor_index_count == monitor) break; } - drmModeFreeConnector(g_drm_connector); - g_drm_connector = nullptr; + drmModeFreeConnector(g_drm->drm_connector); + g_drm->drm_connector = nullptr; } - if (!g_drm_connector) + if (!g_drm->drm_connector) { INFO_LOG(VIDEO, "[DRM]: Couldn't get device connector.\n"); return false; @@ -514,63 +475,42 @@ bool drm_get_encoder(int fd) { unsigned i; - for (i = 0; (int)i < g_drm_resources->count_encoders; i++) + for (i = 0; (int)i < g_drm->drm_resources->count_encoders; i++) { - g_drm_encoder = drmModeGetEncoder(fd, g_drm_resources->encoders[i]); + g_drm->drm_encoder = drmModeGetEncoder(fd, g_drm->drm_resources->encoders[i]); - if (!g_drm_encoder) + if (!g_drm->drm_encoder) continue; - if (g_drm_encoder->encoder_id == g_drm_connector->encoder_id) + if (g_drm->drm_encoder->encoder_id == g_drm->drm_connector->encoder_id) break; - drmModeFreeEncoder(g_drm_encoder); - g_drm_encoder = nullptr; + drmModeFreeEncoder(g_drm->drm_encoder); + g_drm->drm_encoder = nullptr; } - if (!g_drm_encoder) + if (!g_drm->drm_encoder) { INFO_LOG(VIDEO, "[DRM]: Couldn't find DRM encoder.\n"); return false; } - for (i = 0; (int)i < g_drm_connector->count_modes; i++) + for (i = 0; (int)i < g_drm->drm_connector->count_modes; i++) { - INFO_LOG(VIDEO, "[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", i, g_drm_connector->modes[i].name, - g_drm_connector->modes[i].hdisplay, g_drm_connector->modes[i].vdisplay, - g_drm_connector->modes[i].vrefresh); + INFO_LOG(VIDEO, "[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", i, g_drm->drm_connector->modes[i].name, + g_drm->drm_connector->modes[i].hdisplay, g_drm->drm_connector->modes[i].vdisplay, + g_drm->drm_connector->modes[i].vrefresh); } return true; } -void drm_setup(int fd) -{ - g_crtc_id = g_drm_encoder->crtc_id; - g_connector_id = g_drm_connector->connector_id; - g_orig_crtc = drmModeGetCrtc(fd, g_crtc_id); - if (!g_orig_crtc) - INFO_LOG(VIDEO, "[DRM]: Cannot find original CRTC.\n"); -} - -float drm_get_refresh_rate(void* data) -{ - float refresh_rate = 0.0f; - - if (g_drm_mode) - { - refresh_rate = g_drm_mode->clock * 1000.0f / g_drm_mode->htotal / g_drm_mode->vtotal; - } - - return refresh_rate; -} - static void drm_fb_destroy_callback(struct gbm_bo* bo, void* data) { struct drm_fb* fb = (struct drm_fb*)data; if (fb && fb->fb_id) - drmModeRmFB(g_drm_fd, fb->fb_id); + drmModeRmFB(g_drm->drm_fd, fb->fb_id); free(fb); } @@ -590,7 +530,7 @@ static struct drm_fb* drm_fb_get_from_bo(struct gbm_bo* bo) INFO_LOG(VIDEO, "[KMS]: New FB: %ux%u (stride: %u).\n", width, height, stride); - ret = drmModeAddFB(g_drm_fd, width, height, 24, 32, stride, handle, &fb->fb_id); + ret = drmModeAddFB(g_drm->drm_fd, width, height, 24, 32, stride, handle, &fb->fb_id); if (ret < 0) goto error; @@ -615,24 +555,6 @@ static void gfx_ctx_drm_swap_interval(void* data, int interval) static void drm_flip_handler(int fd, unsigned frame, unsigned sec, unsigned usec, void* data) { -#if 0 - static unsigned first_page_flip; - static unsigned last_page_flip; - - if (!first_page_flip) - first_page_flip = frame; - - if (last_page_flip) - { - unsigned missed = frame - last_page_flip - 1; - if (missed) - INFO_LOG(VIDEO, "[KMS]: Missed %u VBlank(s) (Frame: %u, DRM frame: %u).\n", - missed, frame - first_page_flip, frame); - } - - last_page_flip = frame; -#endif - *(bool*)data = false; } @@ -677,7 +599,7 @@ static bool gfx_ctx_drm_queue_flip(GFXContextDRMData* drm) if (!fb) fb = (struct drm_fb*)drm_fb_get_from_bo(drm->next_bo); - if (drmModePageFlip(g_drm_fd, g_crtc_id, fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, + if (drmModePageFlip(g_drm->drm_fd, g_drm->crtc_id, fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, &drm->waiting_for_flip) == 0) return true; @@ -692,7 +614,14 @@ static void free_drm_resources(GFXContextDRMData* drm) return; /* Restore original CRTC. */ - drm_restore_crtc(); + if (drm->orig_crtc) + { + drmModeSetCrtc(drm->drm_fd, drm->orig_crtc->crtc_id, drm->orig_crtc->buffer_id, drm->orig_crtc->x, + drm->orig_crtc->y, &drm->connector_id, 1, &drm->orig_crtc->mode); + + drmModeFreeCrtc(drm->orig_crtc); + drm->orig_crtc = nullptr; + } if (drm->gbm_surface) gbm_surface_destroy(drm->gbm_surface); @@ -700,32 +629,32 @@ static void free_drm_resources(GFXContextDRMData* drm) if (drm->gbm_dev) gbm_device_destroy(drm->gbm_dev); - if (g_drm_encoder) - drmModeFreeEncoder(g_drm_encoder); - if (g_drm_connector) - drmModeFreeConnector(g_drm_connector); - if (g_drm_resources) - drmModeFreeResources(g_drm_resources); + if (drm->drm_encoder) + drmModeFreeEncoder(drm->drm_encoder); + if (drm->drm_connector) + drmModeFreeConnector(drm->drm_connector); + if (drm->drm_resources) + drmModeFreeResources(drm->drm_resources); - memset(&g_drm_fds, 0, sizeof(struct pollfd)); - memset(&g_drm_evctx, 0, sizeof(drmEventContext)); + memset(&drm->drm_fds, 0, sizeof(struct pollfd)); + memset(&drm->drm_evctx, 0, sizeof(drmEventContext)); - g_drm_encoder = nullptr; - g_drm_connector = nullptr; - g_drm_resources = nullptr; + drm->drm_encoder = nullptr; + drm->drm_connector = nullptr; + drm->drm_resources = nullptr; if (drm->fd >= 0) { - if (g_drm_fd >= 0) + if (drm->drm_fd >= 0) { - drmDropMaster(g_drm_fd); + drmDropMaster(drm->drm_fd); close(drm->fd); } } drm->gbm_surface = nullptr; drm->gbm_dev = nullptr; - g_drm_fd = -1; + drm->drm_fd = -1; } static void gfx_ctx_drm_destroy_resources(GFXContextDRMData* drm) @@ -740,9 +669,9 @@ static void gfx_ctx_drm_destroy_resources(GFXContextDRMData* drm) free_drm_resources(drm); - g_drm_mode = nullptr; - g_crtc_id = 0; - g_connector_id = 0; + drm->drm_mode = nullptr; + drm->crtc_id = 0; + drm->connector_id = 0; drm->fb_width = 0; drm->fb_height = 0; @@ -771,9 +700,10 @@ static void* gfx_ctx_drm_init() fd = drm->fd; - if (!drm_get_resources(fd)) + drm->drm_resources = drmModeGetResources(fd); + if (!drm->drm_resources) { - INFO_LOG(VIDEO, "[KMS]: drm_get_resources failed\n"); + INFO_LOG(VIDEO, "[KMS]: Couldn't get DRM device resources.\n"); return nullptr; } @@ -789,23 +719,27 @@ static void* gfx_ctx_drm_init() return nullptr; } - drm_setup(fd); + drm->crtc_id = drm->drm_encoder->crtc_id; + drm->connector_id = drm->drm_connector->connector_id; + drm->orig_crtc = drmModeGetCrtc(fd, drm->crtc_id); + if (!drm->orig_crtc) + INFO_LOG(VIDEO, "[DRM]: Cannot find original CRTC.\n"); /* Choose the optimal video mode for get_video_size(): - the current video mode from the CRTC - otherwise pick first connector mode */ - if (g_orig_crtc->mode_valid) + if (drm->orig_crtc->mode_valid) { - drm->fb_width = g_orig_crtc->mode.hdisplay; - drm->fb_height = g_orig_crtc->mode.vdisplay; + drm->fb_width = drm->orig_crtc->mode.hdisplay; + drm->fb_height = drm->orig_crtc->mode.vdisplay; } else { - drm->fb_width = g_drm_connector->modes[0].hdisplay; - drm->fb_height = g_drm_connector->modes[0].vdisplay; + drm->fb_width = drm->drm_connector->modes[0].hdisplay; + drm->fb_height = drm->drm_connector->modes[0].vdisplay; } - drmSetMaster(g_drm_fd); + drmSetMaster(drm->drm_fd); drm->gbm_dev = gbm_create_device(fd); @@ -816,12 +750,12 @@ static void* gfx_ctx_drm_init() } /* Setup the flip handler. */ - g_drm_fds.fd = fd; - g_drm_fds.events = POLLIN; - g_drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; - g_drm_evctx.page_flip_handler = drm_flip_handler; + drm->drm_fds.fd = fd; + drm->drm_fds.events = POLLIN; + drm->drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; + drm->drm_evctx.page_flip_handler = drm_flip_handler; - g_drm_fd = fd; + drm->drm_fd = fd; return drm; } @@ -932,7 +866,7 @@ static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned heig * If not fullscreen, we get desired windowed size, * which is not appropriate. */ if ((width == 0 && height == 0) || !fullscreen) - g_drm_mode = &g_drm_connector->modes[0]; + drm->drm_mode = &drm->drm_connector->modes[0]; else { /* Try to match refresh_rate as closely as possible. @@ -943,31 +877,31 @@ static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned heig float minimum_fps_diff = 0.0f; /* Find best match. */ - for (i = 0; i < g_drm_connector->count_modes; i++) + for (i = 0; i < drm->drm_connector->count_modes; i++) { float diff; - if (width != g_drm_connector->modes[i].hdisplay || - height != g_drm_connector->modes[i].vdisplay) + if (width != drm->drm_connector->modes[i].hdisplay || + height != drm->drm_connector->modes[i].vdisplay) continue; - diff = fabsf(g_drm_connector->modes[i].vrefresh - video_refresh_rate); + diff = fabsf(drm->drm_connector->modes[i].vrefresh - video_refresh_rate); - if (!g_drm_mode || diff < minimum_fps_diff) + if (!drm->drm_mode || diff < minimum_fps_diff) { - g_drm_mode = &g_drm_connector->modes[i]; + drm->drm_mode = &drm->drm_connector->modes[i]; minimum_fps_diff = diff; } } } - if (!g_drm_mode) + if (!drm->drm_mode) { INFO_LOG(VIDEO, "[KMS/EGL]: Did not find suitable video mode for %u x %u.\n", width, height); goto error; } - drm->fb_width = g_drm_mode->hdisplay; - drm->fb_height = g_drm_mode->vdisplay; + drm->fb_width = drm->drm_mode->hdisplay; + drm->fb_height = drm->drm_mode->vdisplay; /* Create GBM surface. */ drm->gbm_surface = @@ -993,7 +927,7 @@ static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned heig if (!fb) fb = drm_fb_get_from_bo(drm->bo); - ret = drmModeSetCrtc(g_drm_fd, g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode); + ret = drmModeSetCrtc(drm->drm_fd, drm->crtc_id, fb->fb_id, 0, 0, &drm->connector_id, 1, drm->drm_mode); if (ret < 0) { INFO_LOG(VIDEO, "[KMS/EGL]: drmModeSetCrtc failed\n"); From c6a374bae4c0b1c990d06acb4266ca60358b9419 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 19:03:32 +0200 Subject: [PATCH 20/26] Refactor (3) --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 106 ++++++++----------- 1 file changed, 44 insertions(+), 62 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index 14c7f45b7b16..726c68a95a5b 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -107,34 +107,9 @@ struct drm_fb /* TODO/FIXME - static globals */ static GFXContextDRMData* g_drm = nullptr; -bool drm_get_encoder(int fd); - /* Restore the original CRTC. */ bool drm_get_connector(int fd); -static void egl_destroy(EGLContextData* egl) -{ - if (egl->dpy) - { - eglMakeCurrent(egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (egl->ctx != EGL_NO_CONTEXT) - eglDestroyContext(egl->dpy, egl->ctx); - - if (egl->surf != EGL_NO_SURFACE) - eglDestroySurface(egl->dpy, egl->surf); - eglTerminate(egl->dpy); - } - - /* Be as careful as possible in deinit. - * If we screw up, any TTY will not restore. - */ - - egl->ctx = EGL_NO_CONTEXT; - egl->surf = EGL_NO_SURFACE; - egl->dpy = EGL_NO_DISPLAY; - egl->config = 0; -} - static void egl_swap_buffers(void* data) { EGLContextData* egl = (EGLContextData*)data; @@ -144,26 +119,6 @@ static void egl_swap_buffers(void* data) } } -static void egl_set_swap_interval(EGLContextData* egl, int interval) -{ - /* Can be called before initialization. - * Some contexts require that swap interval - * is known at startup time. - */ - egl->interval = interval; - - if (egl->dpy == EGL_NO_DISPLAY) - return; - if (!eglGetCurrentContext()) - return; - - INFO_LOG(VIDEO, "[EGL]: eglSwapInterval(%u)\n", interval); - if (!eglSwapInterval(egl->dpy, interval)) - { - INFO_LOG(VIDEO, "[EGL]: eglSwapInterval() failed 0x%x.\n", eglGetError()); - } -} - static bool check_egl_version(int minMajorVersion, int minMinorVersion) { int count; @@ -213,10 +168,9 @@ static bool check_egl_client_extension(const char* name) return false; } -static bool check_egl_display_extension(void* data, const char* name) +static bool check_egl_display_extension(EGLContextData* egl, const char* name) { size_t nameLen; - EGLContextData* egl = (EGLContextData*)data; if (!egl || egl->dpy == EGL_NO_DISPLAY) return false; @@ -543,16 +497,6 @@ static struct drm_fb* drm_fb_get_from_bo(struct gbm_bo* bo) return nullptr; } -static void gfx_ctx_drm_swap_interval(void* data, int interval) -{ - GFXContextDRMData* drm = (GFXContextDRMData*)data; - drm->interval = interval; - - if (interval > 1) - INFO_LOG(VIDEO, - "[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); -} - static void drm_flip_handler(int fd, unsigned frame, unsigned sec, unsigned usec, void* data) { *(bool*)data = false; @@ -665,7 +609,25 @@ static void gfx_ctx_drm_destroy_resources(GFXContextDRMData* drm) /* Make sure we acknowledge all page-flips. */ gfx_ctx_drm_wait_flip(drm, true); - egl_destroy(&drm->egl); + if (drm->egl.dpy) + { + eglMakeCurrent(drm->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (drm->egl.ctx != EGL_NO_CONTEXT) + eglDestroyContext(drm->egl.dpy, drm->egl.ctx); + + if (drm->egl.surf != EGL_NO_SURFACE) + eglDestroySurface(drm->egl.dpy, drm->egl.surf); + eglTerminate(drm->egl.dpy); + } + + /* Be as careful as possible in deinit. + * If we screw up, any TTY will not restore. + */ + + drm->egl.ctx = EGL_NO_CONTEXT; + drm->egl.surf = EGL_NO_SURFACE; + drm->egl.dpy = EGL_NO_DISPLAY; + drm->egl.config = 0; free_drm_resources(drm); @@ -986,10 +948,30 @@ void GLContextEGLDRM::Swap() gfx_ctx_drm_wait_flip(g_drm, true); } + void GLContextEGLDRM::SwapInterval(int interval) { - gfx_ctx_drm_swap_interval(g_drm, interval); - egl_set_swap_interval(m_egl, interval); + g_drm->interval = interval; + if (interval > 1) + INFO_LOG(VIDEO, + "[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); + + /* Can be called before initialization. + * Some contexts require that swap interval + * is known at startup time. + */ + m_egl->interval = interval; + + if (m_egl->dpy == EGL_NO_DISPLAY) + return; + if (!eglGetCurrentContext()) + return; + + INFO_LOG(VIDEO, "[EGL]: eglSwapInterval(%u)\n", interval); + if (!eglSwapInterval(m_egl->dpy, interval)) + { + INFO_LOG(VIDEO, "[EGL]: eglSwapInterval() failed 0x%x.\n", eglGetError()); + } } void* GLContextEGLDRM::GetFuncAddress(const std::string& name) @@ -1057,7 +1039,7 @@ bool GLContextEGLDRM::CreateWindowSurface() if (m_supports_surfaceless) { m_egl->surf = EGL_NO_SURFACE; - INFO_LOG(VIDEO, "\nCreated surfaceless context\n"); + INFO_LOG(VIDEO, "\nCreated surfaceless EGL shared context\n"); return true; } @@ -1065,7 +1047,7 @@ bool GLContextEGLDRM::CreateWindowSurface() { if (!egl_create_surface(m_egl, (EGLNativeWindowType)g_drm->gbm_surface)) { - INFO_LOG(VIDEO, "\negl_create_surface failed, trying pbuffer failed 0x%x\n", eglGetError()); + INFO_LOG(VIDEO, "\negl_create_surface failed (error 0x%x), trying pbuffer instead...\n", eglGetError()); goto pbuffer; } // Get dimensions from the surface. From c9c4e4341c496ce351af0a0c65a6068c46f01af3 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 19:25:36 +0200 Subject: [PATCH 21/26] Move helper functions to static --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index 726c68a95a5b..a7ae0a6dbfb1 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -107,9 +107,6 @@ struct drm_fb /* TODO/FIXME - static globals */ static GFXContextDRMData* g_drm = nullptr; -/* Restore the original CRTC. */ -bool drm_get_connector(int fd); - static void egl_swap_buffers(void* data) { EGLContextData* egl = (EGLContextData*)data; @@ -369,7 +366,7 @@ static bool drm_wait_flip(int timeout) return false; } -bool drm_get_connector(int fd) +static bool drm_get_connector(int fd) { unsigned i; unsigned monitor_index_count = 0; @@ -425,7 +422,7 @@ bool drm_get_connector(int fd) return true; } -bool drm_get_encoder(int fd) +static bool drm_get_encoder(int fd) { unsigned i; From d6fbe009dc0fa3ea29d8dd6b12cf7712154dc3ca Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 20:58:50 +0200 Subject: [PATCH 22/26] Better conditional compilation support for EGL/DRM (should pass Dolphin CI) --- CMakeLists.txt | 6 ++++++ Source/Core/Common/CMakeLists.txt | 2 -- Source/Core/Common/GL/GLContext.cpp | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 26484938a324..91d8341bd58a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -456,6 +456,12 @@ if(ENABLE_EGL) if(EGL_FOUND) add_definitions(-DHAVE_EGL=1) message(STATUS "EGL OpenGL interface enabled") + find_package(Libdrm) + find_package(Libgbm) + if(LIBDRM_FOUND AND LIBGBM_FOUND) + add_definitions(-DHAVE_DRM=1) + message(STATUS "EGL/DRM/GBM support enabled") + endif() else() message(WARNING "EGL support enabled but not found. This build will not support EGL.") endif() diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 6e7574b7c8d6..f40dff90a59d 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -222,8 +222,6 @@ target_sources(common PRIVATE ) if(ENABLE_EGL AND EGL_FOUND) - find_package(Libdrm) - find_package(Libgbm) if (LIBDRM_FOUND AND LIBGBM_FOUND) target_sources(common PRIVATE GL/GLInterface/EGL.cpp diff --git a/Source/Core/Common/GL/GLContext.cpp b/Source/Core/Common/GL/GLContext.cpp index f5adaab71ab6..25ff342d6ca4 100644 --- a/Source/Core/Common/GL/GLContext.cpp +++ b/Source/Core/Common/GL/GLContext.cpp @@ -17,7 +17,9 @@ #endif #if HAVE_EGL #include "Common/GL/GLInterface/EGL.h" +#if HAVE_DRM #include "Common/GL/GLInterface/EGLDRM.h" +#endif #if HAVE_X11 #include "Common/GL/GLInterface/EGLX11.h" #endif From b9eaa05b0b4111658005fabba05f93a4bac475e6 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 21:09:56 +0200 Subject: [PATCH 23/26] Fix missing #ifdef --- Source/Core/Common/GL/GLContext.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Core/Common/GL/GLContext.cpp b/Source/Core/Common/GL/GLContext.cpp index 25ff342d6ca4..9d33b1cff78b 100644 --- a/Source/Core/Common/GL/GLContext.cpp +++ b/Source/Core/Common/GL/GLContext.cpp @@ -113,8 +113,10 @@ std::unique_ptr GLContext::Create(const WindowSystemInfo& wsi, bool s #if HAVE_EGL if (wsi.type == WindowSystemType::Headless || wsi.type == WindowSystemType::FBDev) context = std::make_unique(); +#if HAVE_DRM else if (wsi.type == WindowSystemType::DRM) context = std::make_unique(); +#endif #endif if (!context) From 1eea311b76ca66b8742c12dd9e16875f0502078c Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Fri, 7 Aug 2020 21:11:38 +0200 Subject: [PATCH 24/26] Fix lint checks --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 16 ++++++++++------ Source/Core/Common/GL/GLInterface/EGLDRM.h | 1 - 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index a7ae0a6dbfb1..367e875371fd 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -403,7 +403,8 @@ static bool drm_get_connector(int fd) if (!g_drm->drm_connector) continue; - if (g_drm->drm_connector->connection == DRM_MODE_CONNECTED && g_drm->drm_connector->count_modes > 0) + if (g_drm->drm_connector->connection == DRM_MODE_CONNECTED && + g_drm->drm_connector->count_modes > 0) { monitor_index_count++; if (monitor_index_count == monitor) @@ -557,8 +558,9 @@ static void free_drm_resources(GFXContextDRMData* drm) /* Restore original CRTC. */ if (drm->orig_crtc) { - drmModeSetCrtc(drm->drm_fd, drm->orig_crtc->crtc_id, drm->orig_crtc->buffer_id, drm->orig_crtc->x, - drm->orig_crtc->y, &drm->connector_id, 1, &drm->orig_crtc->mode); + drmModeSetCrtc(drm->drm_fd, drm->orig_crtc->crtc_id, drm->orig_crtc->buffer_id, + drm->orig_crtc->x, drm->orig_crtc->y, &drm->connector_id, 1, + &drm->orig_crtc->mode); drmModeFreeCrtc(drm->orig_crtc); drm->orig_crtc = nullptr; @@ -886,7 +888,8 @@ static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned heig if (!fb) fb = drm_fb_get_from_bo(drm->bo); - ret = drmModeSetCrtc(drm->drm_fd, drm->crtc_id, fb->fb_id, 0, 0, &drm->connector_id, 1, drm->drm_mode); + ret = drmModeSetCrtc(drm->drm_fd, drm->crtc_id, fb->fb_id, 0, 0, &drm->connector_id, 1, + drm->drm_mode); if (ret < 0) { INFO_LOG(VIDEO, "[KMS/EGL]: drmModeSetCrtc failed\n"); @@ -922,7 +925,7 @@ bool GLContextEGLDRM::IsHeadless() const void GLContextEGLDRM::Swap() { - unsigned max_swapchain_images = 2; // double-buffering + unsigned max_swapchain_images = 2; // double-buffering egl_swap_buffers(&g_drm->egl); @@ -1044,7 +1047,8 @@ bool GLContextEGLDRM::CreateWindowSurface() { if (!egl_create_surface(m_egl, (EGLNativeWindowType)g_drm->gbm_surface)) { - INFO_LOG(VIDEO, "\negl_create_surface failed (error 0x%x), trying pbuffer instead...\n", eglGetError()); + INFO_LOG(VIDEO, "\negl_create_surface failed (error 0x%x), trying pbuffer instead...\n", + eglGetError()); goto pbuffer; } // Get dimensions from the surface. diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.h b/Source/Core/Common/GL/GLInterface/EGLDRM.h index 46d361a3a148..ffa6c7af329e 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.h +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.h @@ -21,7 +21,6 @@ struct EGLContextData unsigned major; unsigned minor; - }; class GLContextEGLDRM : public GLContext From 1294d4d6b807cd2775693f742068bdad0c45c35b Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Sat, 8 Aug 2020 11:33:04 +0200 Subject: [PATCH 25/26] Fix crash following refactoring --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 86 ++++++++++---------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index 367e875371fd..f8487619809a 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -98,15 +98,15 @@ struct GFXContextDRMData drmModeEncoder* drm_encoder = nullptr; }; +/* TODO/FIXME - static globals */ +static GFXContextDRMData* g_drm = nullptr; + struct drm_fb { struct gbm_bo* bo; uint32_t fb_id; }; -/* TODO/FIXME - static globals */ -static GFXContextDRMData* g_drm = nullptr; - static void egl_swap_buffers(void* data) { EGLContextData* egl = (EGLContextData*)data; @@ -347,26 +347,26 @@ static bool egl_create_surface(EGLContextData* egl, void* native_window) return true; } -static bool drm_wait_flip(int timeout) +static bool drm_wait_flip(GFXContextDRMData* drm, int timeout) { - g_drm->drm_fds.revents = 0; + drm->drm_fds.revents = 0; - if (poll(&g_drm->drm_fds, 1, timeout) < 0) + if (poll(&drm->drm_fds, 1, timeout) < 0) return false; - if (g_drm->drm_fds.revents & (POLLHUP | POLLERR)) + if (drm->drm_fds.revents & (POLLHUP | POLLERR)) return false; - if (g_drm->drm_fds.revents & POLLIN) + if (drm->drm_fds.revents & POLLIN) { - drmHandleEvent(g_drm->drm_fd, &g_drm->drm_evctx); + drmHandleEvent(drm->drm_fd, &drm->drm_evctx); return true; } return false; } -static bool drm_get_connector(int fd) +static bool drm_get_connector(GFXContextDRMData* drm, int fd) { unsigned i; unsigned monitor_index_count = 0; @@ -374,11 +374,11 @@ static bool drm_get_connector(int fd) /* Enumerate all connectors. */ - INFO_LOG(VIDEO, "[DRM]: Found %d connectors.\n", g_drm->drm_resources->count_connectors); + INFO_LOG(VIDEO, "[DRM]: Found %d connectors.\n", drm->drm_resources->count_connectors); - for (i = 0; (int)i < g_drm->drm_resources->count_connectors; i++) + for (i = 0; (int)i < drm->drm_resources->count_connectors; i++) { - drmModeConnectorPtr conn = drmModeGetConnector(fd, g_drm->drm_resources->connectors[i]); + drmModeConnectorPtr conn = drmModeGetConnector(fd, drm->drm_resources->connectors[i]); if (conn) { @@ -397,25 +397,24 @@ static bool drm_get_connector(int fd) monitor_index_count = 0; - for (i = 0; (int)i < g_drm->drm_resources->count_connectors; i++) + for (i = 0; (int)i < drm->drm_resources->count_connectors; i++) { - g_drm->drm_connector = drmModeGetConnector(fd, g_drm->drm_resources->connectors[i]); + drm->drm_connector = drmModeGetConnector(fd, drm->drm_resources->connectors[i]); - if (!g_drm->drm_connector) + if (!drm->drm_connector) continue; - if (g_drm->drm_connector->connection == DRM_MODE_CONNECTED && - g_drm->drm_connector->count_modes > 0) + if (drm->drm_connector->connection == DRM_MODE_CONNECTED && drm->drm_connector->count_modes > 0) { monitor_index_count++; if (monitor_index_count == monitor) break; } - drmModeFreeConnector(g_drm->drm_connector); - g_drm->drm_connector = nullptr; + drmModeFreeConnector(drm->drm_connector); + drm->drm_connector = nullptr; } - if (!g_drm->drm_connector) + if (!drm->drm_connector) { INFO_LOG(VIDEO, "[DRM]: Couldn't get device connector.\n"); return false; @@ -423,35 +422,35 @@ static bool drm_get_connector(int fd) return true; } -static bool drm_get_encoder(int fd) +static bool drm_get_encoder(GFXContextDRMData* drm, int fd) { unsigned i; - for (i = 0; (int)i < g_drm->drm_resources->count_encoders; i++) + for (i = 0; (int)i < drm->drm_resources->count_encoders; i++) { - g_drm->drm_encoder = drmModeGetEncoder(fd, g_drm->drm_resources->encoders[i]); + drm->drm_encoder = drmModeGetEncoder(fd, drm->drm_resources->encoders[i]); - if (!g_drm->drm_encoder) + if (!drm->drm_encoder) continue; - if (g_drm->drm_encoder->encoder_id == g_drm->drm_connector->encoder_id) + if (drm->drm_encoder->encoder_id == drm->drm_connector->encoder_id) break; - drmModeFreeEncoder(g_drm->drm_encoder); - g_drm->drm_encoder = nullptr; + drmModeFreeEncoder(drm->drm_encoder); + drm->drm_encoder = nullptr; } - if (!g_drm->drm_encoder) + if (!drm->drm_encoder) { INFO_LOG(VIDEO, "[DRM]: Couldn't find DRM encoder.\n"); return false; } - for (i = 0; (int)i < g_drm->drm_connector->count_modes; i++) + for (i = 0; (int)i < drm->drm_connector->count_modes; i++) { - INFO_LOG(VIDEO, "[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", i, g_drm->drm_connector->modes[i].name, - g_drm->drm_connector->modes[i].hdisplay, g_drm->drm_connector->modes[i].vdisplay, - g_drm->drm_connector->modes[i].vrefresh); + INFO_LOG(VIDEO, "[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", i, drm->drm_connector->modes[i].name, + drm->drm_connector->modes[i].hdisplay, drm->drm_connector->modes[i].vdisplay, + drm->drm_connector->modes[i].vrefresh); } return true; @@ -461,13 +460,13 @@ static void drm_fb_destroy_callback(struct gbm_bo* bo, void* data) { struct drm_fb* fb = (struct drm_fb*)data; - if (fb && fb->fb_id) + if (fb && fb->fb_id && g_drm) drmModeRmFB(g_drm->drm_fd, fb->fb_id); free(fb); } -static struct drm_fb* drm_fb_get_from_bo(struct gbm_bo* bo) +static struct drm_fb* drm_fb_get_from_bo(GFXContextDRMData* drm, struct gbm_bo* bo) { int ret; unsigned width, height, stride, handle; @@ -482,7 +481,7 @@ static struct drm_fb* drm_fb_get_from_bo(struct gbm_bo* bo) INFO_LOG(VIDEO, "[KMS]: New FB: %ux%u (stride: %u).\n", width, height, stride); - ret = drmModeAddFB(g_drm->drm_fd, width, height, 24, 32, stride, handle, &fb->fb_id); + ret = drmModeAddFB(drm->drm_fd, width, height, 24, 32, stride, handle, &fb->fb_id); if (ret < 0) goto error; @@ -512,15 +511,12 @@ static bool gfx_ctx_drm_wait_flip(GFXContextDRMData* drm, bool block) while (drm->waiting_for_flip) { - if (!drm_wait_flip(timeout)) + if (!drm_wait_flip(drm, timeout)) break; } if (drm->waiting_for_flip) - { - INFO_LOG(VIDEO, "\nwait flip 2"); return true; - } /* Page flip has taken place. */ @@ -539,9 +535,9 @@ static bool gfx_ctx_drm_queue_flip(GFXContextDRMData* drm) fb = (struct drm_fb*)gbm_bo_get_user_data(drm->next_bo); if (!fb) - fb = (struct drm_fb*)drm_fb_get_from_bo(drm->next_bo); + fb = (struct drm_fb*)drm_fb_get_from_bo(drm, drm->next_bo); - if (drmModePageFlip(g_drm->drm_fd, g_drm->crtc_id, fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, + if (drmModePageFlip(drm->drm_fd, drm->crtc_id, fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, &drm->waiting_for_flip) == 0) return true; @@ -668,13 +664,13 @@ static void* gfx_ctx_drm_init() return nullptr; } - if (!drm_get_connector(fd)) + if (!drm_get_connector(drm, fd)) { INFO_LOG(VIDEO, "[KMS]: drm_get_connector failed\n"); return nullptr; } - if (!drm_get_encoder(fd)) + if (!drm_get_encoder(drm, fd)) { INFO_LOG(VIDEO, "[KMS]: drm_get_encoder failed\n"); return nullptr; @@ -886,7 +882,7 @@ static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned heig fb = (struct drm_fb*)gbm_bo_get_user_data(drm->bo); if (!fb) - fb = drm_fb_get_from_bo(drm->bo); + fb = drm_fb_get_from_bo(drm, drm->bo); ret = drmModeSetCrtc(drm->drm_fd, drm->crtc_id, fb->fb_id, 0, 0, &drm->connector_id, 1, drm->drm_mode); From 0b160db48796f727311cea16072174d96b784f80 Mon Sep 17 00:00:00 2001 From: Romain TISSERAND Date: Tue, 11 Aug 2020 15:46:26 +0200 Subject: [PATCH 26/26] Refactor/rework EGLDRM as C++ --- Source/Core/Common/GL/GLInterface/EGLDRM.cpp | 976 +++++++++---------- Source/Core/Common/GL/GLInterface/EGLDRM.h | 95 +- Source/Core/DolphinQt/MainWindow.cpp | 2 + 3 files changed, 538 insertions(+), 535 deletions(-) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp index f8487619809a..cc494ae3236c 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.cpp @@ -2,47 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -// EGL DRM GBM code based on RetroArch, RetroArch licenses follows - -/* RetroArch - A frontend for libretro. - * Copyright (c) 2011-2017 - Daniel De Matteis - * - * RetroArch 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 Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch 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 RetroArch. - * If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - #include "Common/GL/GLInterface/EGLDRM.h" #include "Common/Logging/Log.h" #include "Core/HW/VideoInterface.h" //for TargetRefreshRate @@ -69,37 +28,20 @@ #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB #endif /* EGL_KHR_create_context */ -using EGLAcceptConfigCB = bool (*)(void* display_data, EGLDisplay dpy, EGLConfig config); - -struct GFXContextDRMData -{ - EGLContextData egl; - int fd; - int interval; - unsigned fb_width; - unsigned fb_height; +#define DRM_EGL_ATTRIBS_BASE \ + EGL_SURFACE_TYPE, 0 /*EGL_WINDOW_BIT*/, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, \ + EGL_ALPHA_SIZE, 0, EGL_DEPTH_SIZE, 0 - bool waiting_for_flip; - struct gbm_bo* bo; - struct gbm_bo* next_bo; - struct gbm_surface* gbm_surface; - struct gbm_device* gbm_dev; - - drmEventContext drm_evctx; - struct pollfd drm_fds; - uint32_t connector_id = 0; - int drm_fd = 0; - uint32_t crtc_id = 0; - drmModeCrtc* orig_crtc = nullptr; - drmModeConnector* drm_connector = nullptr; - drmModeModeInfo* drm_mode = nullptr; - - drmModeRes* drm_resources = nullptr; - drmModeEncoder* drm_encoder = nullptr; +#ifdef EGL_KHR_create_context +static const EGLint egl_attribs_gles3[] = { + DRM_EGL_ATTRIBS_BASE, + EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES3_BIT_KHR, + EGL_NONE, }; +#endif -/* TODO/FIXME - static globals */ -static GFXContextDRMData* g_drm = nullptr; +EGLDRM* GLContextEGLDRM::g_drm = nullptr; struct drm_fb { @@ -107,38 +49,41 @@ struct drm_fb uint32_t fb_id; }; -static void egl_swap_buffers(void* data) +static void drm_flip_handler(int fd, unsigned frame, unsigned sec, unsigned usec, void* data) { - EGLContextData* egl = (EGLContextData*)data; - if (egl && egl->dpy != EGL_NO_DISPLAY && egl->surf != EGL_NO_SURFACE) - { - eglSwapBuffers(egl->dpy, egl->surf); - } + *(bool*)data = false; } -static bool check_egl_version(int minMajorVersion, int minMinorVersion) +static bool gbm_choose_xrgb8888_cb(void* display_data, EGLDisplay dpy, EGLConfig config) { - int count; - int major, minor; - const char* str = eglQueryString(EGL_NO_DISPLAY, EGL_VERSION); + EGLint r, g, b, id; + (void)display_data; - if (!str) + /* Makes sure we have 8 bit color. */ + if (!eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r)) + return false; + if (!eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g)) + return false; + if (!eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b)) return false; - count = sscanf(str, "%d.%d", &major, &minor); - if (count != 2) + if (r != 8 || g != 8 || b != 8) return false; - if (major < minMajorVersion) + if (!eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &id)) return false; - if (major > minMajorVersion) - return true; + return id == GBM_FORMAT_XRGB8888; +} - if (minor >= minMinorVersion) - return true; +static void drm_fb_destroy_callback(struct gbm_bo* bo, void* data) +{ + struct drm_fb* fb = (struct drm_fb*)data; - return false; + if (fb && fb->fb_id && GLContextEGLDRM::GetDrm()) + drmModeRmFB(GLContextEGLDRM::GetDrm()->GetDrmFd(), fb->fb_id); + + free(fb); } static bool check_egl_client_extension(const char* name) @@ -192,181 +137,266 @@ static bool check_egl_display_extension(EGLContextData* egl, const char* name) return false; } -static EGLDisplay get_egl_display(EGLenum platform, void* native) +static bool check_egl_version(int minMajorVersion, int minMinorVersion) { - if (platform != EGL_NONE) - { - /* If the client library supports at least EGL 1.5, then we can call - * eglGetPlatformDisplay. Otherwise, see if eglGetPlatformDisplayEXT - * is available. */ -#if defined(EGL_VERSION_1_5) - if (check_egl_version(1, 5)) - { - typedef EGLDisplay(EGLAPIENTRY * pfn_eglGetPlatformDisplay)( - EGLenum platform, void* native_display, const EGLAttrib* attrib_list); - pfn_eglGetPlatformDisplay ptr_eglGetPlatformDisplay; + int count; + int major, minor; + const char* str = eglQueryString(EGL_NO_DISPLAY, EGL_VERSION); - INFO_LOG(VIDEO, "[EGL] Found EGL client version >= 1.5, trying eglGetPlatformDisplay\n"); - ptr_eglGetPlatformDisplay = - (pfn_eglGetPlatformDisplay)eglGetProcAddress("eglGetPlatformDisplay"); + if (!str) + return false; - if (ptr_eglGetPlatformDisplay) - { - EGLDisplay dpy = ptr_eglGetPlatformDisplay(platform, native, nullptr); - if (dpy != EGL_NO_DISPLAY) - return dpy; - } - } -#endif /* defined(EGL_VERSION_1_5) */ + count = sscanf(str, "%d.%d", &major, &minor); + if (count != 2) + return false; -#if defined(EGL_EXT_platform_base) - if (check_egl_client_extension("EGL_EXT_platform_base")) - { - PFNEGLGETPLATFORMDISPLAYEXTPROC ptr_eglGetPlatformDisplayEXT; + if (major < minMajorVersion) + return false; - INFO_LOG(VIDEO, "[EGL] Found EGL_EXT_platform_base, trying eglGetPlatformDisplayEXT\n"); - ptr_eglGetPlatformDisplayEXT = - (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT"); + if (major > minMajorVersion) + return true; - if (ptr_eglGetPlatformDisplayEXT) - { - EGLDisplay dpy = ptr_eglGetPlatformDisplayEXT(platform, native, nullptr); - if (dpy != EGL_NO_DISPLAY) - return dpy; - } - } -#endif /* defined(EGL_EXT_platform_base) */ - } + if (minor >= minMinorVersion) + return true; - /* Either the caller didn't provide a platform type, or the EGL - * implementation doesn't support eglGetPlatformDisplay. In this case, try - * eglGetDisplay and hope for the best. */ - INFO_LOG(VIDEO, "[EGL] Falling back to eglGetDisplay\n"); - return eglGetDisplay((EGLNativeDisplayType)native); + return false; } -static bool egl_init_context_common(EGLContextData* egl, EGLint* count, const EGLint* attrib_ptr, - EGLAcceptConfigCB cb, void* display_data) +struct drm_fb* EGLDRM::GetFbFromBo(struct gbm_bo* gbm_bo) { - EGLint i; - EGLint matched = 0; - EGLConfig* configs = nullptr; - if (!egl) + int ret; + unsigned width, height, stride, handle; + struct drm_fb* fb = (struct drm_fb*)calloc(1, sizeof(*fb)); + + fb->bo = gbm_bo; + + width = gbm_bo_get_width(gbm_bo); + height = gbm_bo_get_height(gbm_bo); + stride = gbm_bo_get_stride(gbm_bo); + handle = gbm_bo_get_handle(gbm_bo).u32; + + INFO_LOG(VIDEO, "[KMS]: New FB: %ux%u (stride: %u).\n", width, height, stride); + + ret = drmModeAddFB(this->m_drm_fd, width, height, 24, 32, stride, handle, &fb->fb_id); + if (ret < 0) + goto error; + + gbm_bo_set_user_data(gbm_bo, fb, drm_fb_destroy_callback); + return fb; + +error: + INFO_LOG(VIDEO, "[KMS]: Failed to create FB: %s\n", strerror(errno)); + free(fb); + return nullptr; +} + +bool EGLDRM::WaitFlip(bool block) +{ + int timeout = 0; + + if (!this->m_waiting_for_flip) return false; - if (!eglGetConfigs(egl->dpy, nullptr, 0, count) || *count < 1) + if (block) + timeout = -1; + + while (this->m_waiting_for_flip) { - INFO_LOG(VIDEO, "[EGL]: No configs to choose from.\n"); + if (!DrmWaitFlip(timeout)) + break; + } + + if (this->m_waiting_for_flip) + return true; + + /* Page flip has taken place. */ + + /* This buffer is not on-screen anymore. Release it to GBM. */ + gbm_surface_release_buffer(this->m_gbm_surface, this->m_bo); + + /* This buffer is being shown now. */ + this->m_bo = this->m_next_bo; + return false; +} + +bool EGLDRM::QueueFlip() +{ + struct drm_fb* fb = nullptr; + + this->m_next_bo = gbm_surface_lock_front_buffer(this->m_gbm_surface); + fb = (struct drm_fb*)gbm_bo_get_user_data(this->m_next_bo); + + if (!fb) + fb = (struct drm_fb*)GetFbFromBo(this->m_next_bo); + + if (drmModePageFlip(this->m_drm_fd, this->m_crtc_id, fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, + &this->m_waiting_for_flip) == 0) + return true; + + /* Failed to queue page flip. */ + INFO_LOG(VIDEO, "\nFailed to queue page flip\n"); + return false; +} + +bool EGLDRM::Initialize() +{ + this->m_fd = -1; + + FreeResources(); + + this->m_fd = open("/dev/dri/card0", O_RDWR); + if (this->m_fd < 0) + { + INFO_LOG(VIDEO, "[KMS]: Couldn't open DRM device.\n"); return false; } - configs = (EGLConfig*)malloc(*count * sizeof(*configs)); - if (!configs) + this->m_drm_resources = drmModeGetResources(this->m_fd); + if (!this->m_drm_resources) + { + INFO_LOG(VIDEO, "[KMS]: DRM couldn't get device resources.\n"); return false; + } - if (!eglChooseConfig(egl->dpy, attrib_ptr, configs, *count, &matched) || !matched) + if (!GetConnector(this->m_fd)) { - INFO_LOG(VIDEO, "[EGL]: No EGL configs with appropriate attributes.\n"); + INFO_LOG(VIDEO, "[KMS]: DRM GetConnector failed\n"); return false; } - for (i = 0; i < *count; i++) + if (!GetEncoder(this->m_fd)) { - if (!cb || cb(display_data, egl->dpy, configs[i])) - { - egl->config = configs[i]; - break; - } + INFO_LOG(VIDEO, "[KMS]: DRM GetEncoder failed\n"); + return false; } - free(configs); + this->m_crtc_id = this->m_drm_encoder->crtc_id; + this->m_connector_id = this->m_drm_connector->connector_id; + this->m_orig_crtc = drmModeGetCrtc(this->m_fd, this->m_crtc_id); + if (!this->m_orig_crtc) + INFO_LOG(VIDEO, "[DRM]: Cannot find original CRTC.\n"); - if (i == *count) + /* Choose the optimal video mode for get_video_size(): + - the current video mode from the CRTC + - otherwise pick first connector mode */ + if (this->m_orig_crtc->mode_valid) { - INFO_LOG(VIDEO, "[EGL]: No EGL config found which satifies requirements.\n"); - return false; + this->m_fb_width = this->m_orig_crtc->mode.hdisplay; + this->m_fb_height = this->m_orig_crtc->mode.vdisplay; + } + else + { + this->m_fb_width = this->m_drm_connector->modes[0].hdisplay; + this->m_fb_height = this->m_drm_connector->modes[0].vdisplay; } - return true; -} + drmSetMaster(this->m_drm_fd); -static bool egl_init_context(EGLContextData* egl, EGLenum platform, void* display_data, - EGLint* major, EGLint* minor, EGLint* count, const EGLint* attrib_ptr, - EGLAcceptConfigCB cb) -{ - EGLDisplay dpy = get_egl_display(platform, display_data); + this->m_gbm_dev = gbm_create_device(this->m_fd); - if (dpy == EGL_NO_DISPLAY) + if (!this->m_gbm_dev) { - INFO_LOG(VIDEO, "[EGL]: Couldn't get EGL display.\n"); + INFO_LOG(VIDEO, "[KMS]: Couldn't create GBM device.\n"); return false; } - egl->dpy = dpy; - - if (!eglInitialize(egl->dpy, major, minor)) - return false; + /* Setup the flip handler. */ + this->m_drm_fds.fd = this->m_fd; + this->m_drm_fds.events = POLLIN; + this->m_drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; + this->m_drm_evctx.page_flip_handler = drm_flip_handler; - INFO_LOG(VIDEO, "[EGL]: EGL version: %d.%d\n", *major, *minor); + this->m_drm_fd = this->m_fd; - return egl_init_context_common(egl, count, attrib_ptr, cb, display_data); + /* Initialization complete */ + return true; } -static bool egl_create_context(EGLContextData* egl, const EGLint* egl_attribs) +void EGLDRM::DestroyResources() { - EGLContext ctx = eglCreateContext(egl->dpy, egl->config, EGL_NO_CONTEXT, egl_attribs); - - if (ctx == EGL_NO_CONTEXT) - return false; + /* Make sure we acknowledge all page-flips. */ + WaitFlip(true); - egl->ctx = ctx; + if (this->egl.dpy) + { + eglMakeCurrent(this->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (this->egl.ctx != EGL_NO_CONTEXT) + eglDestroyContext(this->egl.dpy, this->egl.ctx); - return true; -} + if (this->egl.surf != EGL_NO_SURFACE) + eglDestroySurface(this->egl.dpy, this->egl.surf); + eglTerminate(this->egl.dpy); + } -static bool egl_create_surface(EGLContextData* egl, void* native_window) -{ - EGLint window_attribs[] = { - EGL_RENDER_BUFFER, - EGL_BACK_BUFFER, - EGL_NONE, - }; + /* Be as careful as possible in deinit. + * If we screw up, any TTY will not restore. + */ - egl->surf = eglCreateWindowSurface(egl->dpy, egl->config, (NativeWindowType)native_window, - window_attribs); + this->egl.ctx = EGL_NO_CONTEXT; + this->egl.surf = EGL_NO_SURFACE; + this->egl.dpy = EGL_NO_DISPLAY; + this->egl.config = 0; - if (egl->surf == EGL_NO_SURFACE) - return false; + FreeResources(); - /* Connect the context to the surface. */ - if (!eglMakeCurrent(egl->dpy, egl->surf, egl->surf, egl->ctx)) - return false; + this->m_drm_mode = nullptr; + this->m_crtc_id = 0; + this->m_connector_id = 0; - INFO_LOG(VIDEO, "[EGL]: Current context: %p.\n", (void*)eglGetCurrentContext()); + this->m_fb_width = 0; + this->m_fb_height = 0; - return true; + this->m_bo = nullptr; + this->m_next_bo = nullptr; } -static bool drm_wait_flip(GFXContextDRMData* drm, int timeout) +EGLint* EGLDRM::FillDrmEglAttribs(EGLint* attr) { - drm->drm_fds.revents = 0; + *attr++ = EGL_CONTEXT_CLIENT_VERSION; + *attr++ = this->egl.major ? (EGLint)this->egl.major : 2; +#ifdef EGL_KHR_create_context + if (this->egl.minor > 0) + { + *attr++ = EGL_CONTEXT_MINOR_VERSION_KHR; + *attr++ = this->egl.minor; + } +#endif - if (poll(&drm->drm_fds, 1, timeout) < 0) - return false; + *attr = EGL_NONE; + return attr; +} - if (drm->drm_fds.revents & (POLLHUP | POLLERR)) - return false; +void EGLDRM::SwapEglBuffers() +{ + if (egl.dpy != EGL_NO_DISPLAY && egl.surf != EGL_NO_SURFACE) + { + eglSwapBuffers(egl.dpy, egl.surf); + } +} - if (drm->drm_fds.revents & POLLIN) +void EGLDRM::SwapDrm(int interval, int max_swapchain_images) +{ + /* I guess we have to wait for flip to have taken + * place before another flip can be queued up. + * + * If true, we are still waiting for a flip + * (nonblocking mode, so just drop the frame). */ + if (WaitFlip(interval)) { - drmHandleEvent(drm->drm_fd, &drm->drm_evctx); - return true; + INFO_LOG(VIDEO, "\nwait flip"); + return; } - return false; + this->m_waiting_for_flip = QueueFlip(); + + /* Triple-buffered page flips */ + if (max_swapchain_images >= 3 && gbm_surface_has_free_buffers(this->m_gbm_surface)) + return; + + WaitFlip(true); } -static bool drm_get_connector(GFXContextDRMData* drm, int fd) +bool EGLDRM::GetConnector(int connector_fd) { unsigned i; unsigned monitor_index_count = 0; @@ -374,11 +404,12 @@ static bool drm_get_connector(GFXContextDRMData* drm, int fd) /* Enumerate all connectors. */ - INFO_LOG(VIDEO, "[DRM]: Found %d connectors.\n", drm->drm_resources->count_connectors); + INFO_LOG(VIDEO, "[DRM]: Found %d connectors.\n", this->m_drm_resources->count_connectors); - for (i = 0; (int)i < drm->drm_resources->count_connectors; i++) + for (i = 0; (int)i < this->m_drm_resources->count_connectors; i++) { - drmModeConnectorPtr conn = drmModeGetConnector(fd, drm->drm_resources->connectors[i]); + drmModeConnectorPtr conn = + drmModeGetConnector(connector_fd, this->m_drm_resources->connectors[i]); if (conn) { @@ -397,24 +428,25 @@ static bool drm_get_connector(GFXContextDRMData* drm, int fd) monitor_index_count = 0; - for (i = 0; (int)i < drm->drm_resources->count_connectors; i++) + for (i = 0; (int)i < this->m_drm_resources->count_connectors; i++) { - drm->drm_connector = drmModeGetConnector(fd, drm->drm_resources->connectors[i]); + this->m_drm_connector = drmModeGetConnector(connector_fd, this->m_drm_resources->connectors[i]); - if (!drm->drm_connector) + if (!this->m_drm_connector) continue; - if (drm->drm_connector->connection == DRM_MODE_CONNECTED && drm->drm_connector->count_modes > 0) + if (this->m_drm_connector->connection == DRM_MODE_CONNECTED && + this->m_drm_connector->count_modes > 0) { monitor_index_count++; if (monitor_index_count == monitor) break; } - drmModeFreeConnector(drm->drm_connector); - drm->drm_connector = nullptr; + drmModeFreeConnector(this->m_drm_connector); + this->m_drm_connector = nullptr; } - if (!drm->drm_connector) + if (!this->m_drm_connector) { INFO_LOG(VIDEO, "[DRM]: Couldn't get device connector.\n"); return false; @@ -422,353 +454,252 @@ static bool drm_get_connector(GFXContextDRMData* drm, int fd) return true; } -static bool drm_get_encoder(GFXContextDRMData* drm, int fd) +bool EGLDRM::GetEncoder(int encoder_fd) { unsigned i; - for (i = 0; (int)i < drm->drm_resources->count_encoders; i++) + for (i = 0; (int)i < this->m_drm_resources->count_encoders; i++) { - drm->drm_encoder = drmModeGetEncoder(fd, drm->drm_resources->encoders[i]); + this->m_drm_encoder = drmModeGetEncoder(encoder_fd, this->m_drm_resources->encoders[i]); - if (!drm->drm_encoder) + if (!this->m_drm_encoder) continue; - if (drm->drm_encoder->encoder_id == drm->drm_connector->encoder_id) + if (this->m_drm_encoder->encoder_id == this->m_drm_connector->encoder_id) break; - drmModeFreeEncoder(drm->drm_encoder); - drm->drm_encoder = nullptr; + drmModeFreeEncoder(this->m_drm_encoder); + this->m_drm_encoder = nullptr; } - if (!drm->drm_encoder) + if (!this->m_drm_encoder) { INFO_LOG(VIDEO, "[DRM]: Couldn't find DRM encoder.\n"); return false; } - for (i = 0; (int)i < drm->drm_connector->count_modes; i++) + for (i = 0; (int)i < this->m_drm_connector->count_modes; i++) { - INFO_LOG(VIDEO, "[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", i, drm->drm_connector->modes[i].name, - drm->drm_connector->modes[i].hdisplay, drm->drm_connector->modes[i].vdisplay, - drm->drm_connector->modes[i].vrefresh); + INFO_LOG(VIDEO, "[DRM]: Mode %d: (%s) %d x %d, %u Hz\n", i, + this->m_drm_connector->modes[i].name, this->m_drm_connector->modes[i].hdisplay, + this->m_drm_connector->modes[i].vdisplay, this->m_drm_connector->modes[i].vrefresh); } return true; } -static void drm_fb_destroy_callback(struct gbm_bo* bo, void* data) +bool EGLDRM::DrmWaitFlip(int timeout) { - struct drm_fb* fb = (struct drm_fb*)data; - - if (fb && fb->fb_id && g_drm) - drmModeRmFB(g_drm->drm_fd, fb->fb_id); + this->m_drm_fds.revents = 0; - free(fb); -} - -static struct drm_fb* drm_fb_get_from_bo(GFXContextDRMData* drm, struct gbm_bo* bo) -{ - int ret; - unsigned width, height, stride, handle; - struct drm_fb* fb = (struct drm_fb*)calloc(1, sizeof(*fb)); - - fb->bo = bo; - - width = gbm_bo_get_width(bo); - height = gbm_bo_get_height(bo); - stride = gbm_bo_get_stride(bo); - handle = gbm_bo_get_handle(bo).u32; - - INFO_LOG(VIDEO, "[KMS]: New FB: %ux%u (stride: %u).\n", width, height, stride); - - ret = drmModeAddFB(drm->drm_fd, width, height, 24, 32, stride, handle, &fb->fb_id); - if (ret < 0) - goto error; - - gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback); - return fb; - -error: - INFO_LOG(VIDEO, "[KMS]: Failed to create FB: %s\n", strerror(errno)); - free(fb); - return nullptr; -} - -static void drm_flip_handler(int fd, unsigned frame, unsigned sec, unsigned usec, void* data) -{ - *(bool*)data = false; -} - -static bool gfx_ctx_drm_wait_flip(GFXContextDRMData* drm, bool block) -{ - int timeout = 0; - - if (!drm->waiting_for_flip) + if (poll(&this->m_drm_fds, 1, timeout) < 0) return false; - if (block) - timeout = -1; + if (this->m_drm_fds.revents & (POLLHUP | POLLERR)) + return false; - while (drm->waiting_for_flip) + if (this->m_drm_fds.revents & POLLIN) { - if (!drm_wait_flip(drm, timeout)) - break; - } - - if (drm->waiting_for_flip) - return true; - - /* Page flip has taken place. */ - - /* This buffer is not on-screen anymore. Release it to GBM. */ - gbm_surface_release_buffer(drm->gbm_surface, drm->bo); - /* This buffer is being shown now. */ - drm->bo = drm->next_bo; - return false; -} - -static bool gfx_ctx_drm_queue_flip(GFXContextDRMData* drm) -{ - struct drm_fb* fb = nullptr; - - drm->next_bo = gbm_surface_lock_front_buffer(drm->gbm_surface); - fb = (struct drm_fb*)gbm_bo_get_user_data(drm->next_bo); - - if (!fb) - fb = (struct drm_fb*)drm_fb_get_from_bo(drm, drm->next_bo); - - if (drmModePageFlip(drm->drm_fd, drm->crtc_id, fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, - &drm->waiting_for_flip) == 0) + drmHandleEvent(this->m_drm_fd, &this->m_drm_evctx); return true; + } - /* Failed to queue page flip. */ - INFO_LOG(VIDEO, "\nFailed to queue page flip\n"); return false; } -static void free_drm_resources(GFXContextDRMData* drm) +void EGLDRM::FreeResources() { - if (!drm) - return; - /* Restore original CRTC. */ - if (drm->orig_crtc) + if (this->m_orig_crtc) { - drmModeSetCrtc(drm->drm_fd, drm->orig_crtc->crtc_id, drm->orig_crtc->buffer_id, - drm->orig_crtc->x, drm->orig_crtc->y, &drm->connector_id, 1, - &drm->orig_crtc->mode); + drmModeSetCrtc(this->m_drm_fd, this->m_orig_crtc->crtc_id, this->m_orig_crtc->buffer_id, + this->m_orig_crtc->x, this->m_orig_crtc->y, &this->m_connector_id, 1, + &this->m_orig_crtc->mode); - drmModeFreeCrtc(drm->orig_crtc); - drm->orig_crtc = nullptr; + drmModeFreeCrtc(this->m_orig_crtc); + this->m_orig_crtc = nullptr; } - if (drm->gbm_surface) - gbm_surface_destroy(drm->gbm_surface); + if (this->m_gbm_surface) + gbm_surface_destroy(this->m_gbm_surface); - if (drm->gbm_dev) - gbm_device_destroy(drm->gbm_dev); + if (this->m_gbm_dev) + gbm_device_destroy(this->m_gbm_dev); - if (drm->drm_encoder) - drmModeFreeEncoder(drm->drm_encoder); - if (drm->drm_connector) - drmModeFreeConnector(drm->drm_connector); - if (drm->drm_resources) - drmModeFreeResources(drm->drm_resources); + if (this->m_drm_encoder) + drmModeFreeEncoder(this->m_drm_encoder); + if (this->m_drm_connector) + drmModeFreeConnector(this->m_drm_connector); + if (this->m_drm_resources) + drmModeFreeResources(this->m_drm_resources); - memset(&drm->drm_fds, 0, sizeof(struct pollfd)); - memset(&drm->drm_evctx, 0, sizeof(drmEventContext)); + memset(&this->m_drm_fds, 0, sizeof(struct pollfd)); + memset(&this->m_drm_evctx, 0, sizeof(drmEventContext)); - drm->drm_encoder = nullptr; - drm->drm_connector = nullptr; - drm->drm_resources = nullptr; + this->m_drm_encoder = nullptr; + this->m_drm_connector = nullptr; + this->m_drm_resources = nullptr; - if (drm->fd >= 0) + if (this->m_fd >= 0) { - if (drm->drm_fd >= 0) + if (this->m_drm_fd >= 0) { - drmDropMaster(drm->drm_fd); - close(drm->fd); + drmDropMaster(this->m_drm_fd); + close(this->m_fd); } } - drm->gbm_surface = nullptr; - drm->gbm_dev = nullptr; - drm->drm_fd = -1; + this->m_gbm_surface = nullptr; + this->m_gbm_dev = nullptr; + this->m_drm_fd = -1; } -static void gfx_ctx_drm_destroy_resources(GFXContextDRMData* drm) +EGLDisplay EGLDRM::GetEGLDisplay(EGLenum platform, void* native) { - if (!drm) - return; - - /* Make sure we acknowledge all page-flips. */ - gfx_ctx_drm_wait_flip(drm, true); - - if (drm->egl.dpy) + if (platform != EGL_NONE) { - eglMakeCurrent(drm->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (drm->egl.ctx != EGL_NO_CONTEXT) - eglDestroyContext(drm->egl.dpy, drm->egl.ctx); - - if (drm->egl.surf != EGL_NO_SURFACE) - eglDestroySurface(drm->egl.dpy, drm->egl.surf); - eglTerminate(drm->egl.dpy); - } + /* If the client library supports at least EGL 1.5, then we can call + * eglGetPlatformDisplay. Otherwise, see if eglGetPlatformDisplayEXT + * is available. */ +#if defined(EGL_VERSION_1_5) + if (check_egl_version(1, 5)) + { + typedef EGLDisplay(EGLAPIENTRY * pfn_eglGetPlatformDisplay)( + EGLenum platform, void* native_display, const EGLAttrib* attrib_list); + pfn_eglGetPlatformDisplay ptr_eglGetPlatformDisplay; - /* Be as careful as possible in deinit. - * If we screw up, any TTY will not restore. - */ + INFO_LOG(VIDEO, "[EGL] Found EGL client version >= 1.5, trying eglGetPlatformDisplay\n"); + ptr_eglGetPlatformDisplay = + (pfn_eglGetPlatformDisplay)eglGetProcAddress("eglGetPlatformDisplay"); - drm->egl.ctx = EGL_NO_CONTEXT; - drm->egl.surf = EGL_NO_SURFACE; - drm->egl.dpy = EGL_NO_DISPLAY; - drm->egl.config = 0; + if (ptr_eglGetPlatformDisplay) + { + EGLDisplay dpy = ptr_eglGetPlatformDisplay(platform, native, nullptr); + if (dpy != EGL_NO_DISPLAY) + return dpy; + } + } +#endif /* defined(EGL_VERSION_1_5) */ - free_drm_resources(drm); +#if defined(EGL_EXT_platform_base) + if (check_egl_client_extension("EGL_EXT_platform_base")) + { + PFNEGLGETPLATFORMDISPLAYEXTPROC ptr_eglGetPlatformDisplayEXT; - drm->drm_mode = nullptr; - drm->crtc_id = 0; - drm->connector_id = 0; + INFO_LOG(VIDEO, "[EGL] Found EGL_EXT_platform_base, trying eglGetPlatformDisplayEXT\n"); + ptr_eglGetPlatformDisplayEXT = + (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT"); - drm->fb_width = 0; - drm->fb_height = 0; + if (ptr_eglGetPlatformDisplayEXT) + { + EGLDisplay dpy = ptr_eglGetPlatformDisplayEXT(platform, native, nullptr); + if (dpy != EGL_NO_DISPLAY) + return dpy; + } + } +#endif /* defined(EGL_EXT_platform_base) */ + } - drm->bo = nullptr; - drm->next_bo = nullptr; + /* Either the caller didn't provide a platform type, or the EGL + * implementation doesn't support eglGetPlatformDisplay. In this case, try + * eglGetDisplay and hope for the best. */ + INFO_LOG(VIDEO, "[EGL] Falling back to eglGetDisplay\n"); + return eglGetDisplay((EGLNativeDisplayType)native); } -static void* gfx_ctx_drm_init() +bool EGLDRM::InitEGLContext(EGLenum platform, void* display_data, EGLint* major, EGLint* minor, + EGLint* count, const EGLint* attrib_ptr, EGLAcceptConfigCB cb) { - int fd; - GFXContextDRMData* drm = (GFXContextDRMData*)calloc(1, sizeof(GFXContextDRMData)); - - if (!drm) - return nullptr; - drm->fd = -1; - - free_drm_resources(drm); + EGLint i; + EGLint matched = 0; + EGLConfig* configs = nullptr; + EGLDisplay dpy = GetEGLDisplay(platform, display_data); - drm->fd = open("/dev/dri/card0", O_RDWR); - if (drm->fd < 0) + if (dpy == EGL_NO_DISPLAY) { - INFO_LOG(VIDEO, "[KMS]: Couldn't open DRM device.\n"); - return nullptr; + INFO_LOG(VIDEO, "[EGL]: Couldn't get EGL display.\n"); + return false; } - fd = drm->fd; + egl.dpy = dpy; - drm->drm_resources = drmModeGetResources(fd); - if (!drm->drm_resources) - { - INFO_LOG(VIDEO, "[KMS]: Couldn't get DRM device resources.\n"); - return nullptr; - } + if (!eglInitialize(egl.dpy, major, minor)) + return false; - if (!drm_get_connector(drm, fd)) - { - INFO_LOG(VIDEO, "[KMS]: drm_get_connector failed\n"); - return nullptr; - } + INFO_LOG(VIDEO, "[EGL]: EGL version: %d.%d\n", *major, *minor); - if (!drm_get_encoder(drm, fd)) + if (!eglGetConfigs(egl.dpy, nullptr, 0, count) || *count < 1) { - INFO_LOG(VIDEO, "[KMS]: drm_get_encoder failed\n"); - return nullptr; + INFO_LOG(VIDEO, "[EGL]: No configs to choose from.\n"); + return false; } - drm->crtc_id = drm->drm_encoder->crtc_id; - drm->connector_id = drm->drm_connector->connector_id; - drm->orig_crtc = drmModeGetCrtc(fd, drm->crtc_id); - if (!drm->orig_crtc) - INFO_LOG(VIDEO, "[DRM]: Cannot find original CRTC.\n"); + configs = (EGLConfig*)malloc(*count * sizeof(*configs)); + if (!configs) + return false; - /* Choose the optimal video mode for get_video_size(): - - the current video mode from the CRTC - - otherwise pick first connector mode */ - if (drm->orig_crtc->mode_valid) + if (!eglChooseConfig(egl.dpy, attrib_ptr, configs, *count, &matched) || !matched) { - drm->fb_width = drm->orig_crtc->mode.hdisplay; - drm->fb_height = drm->orig_crtc->mode.vdisplay; + INFO_LOG(VIDEO, "[EGL]: No EGL configs with appropriate attributes.\n"); + return false; } - else + + for (i = 0; i < *count; i++) { - drm->fb_width = drm->drm_connector->modes[0].hdisplay; - drm->fb_height = drm->drm_connector->modes[0].vdisplay; + if (!cb || cb(display_data, egl.dpy, configs[i])) + { + egl.config = configs[i]; + break; + } } - drmSetMaster(drm->drm_fd); - - drm->gbm_dev = gbm_create_device(fd); + free(configs); - if (!drm->gbm_dev) + if (i == *count) { - INFO_LOG(VIDEO, "[KMS]: Couldn't create GBM device.\n"); - return nullptr; + INFO_LOG(VIDEO, "[EGL]: No EGL config found which satifies requirements.\n"); + return false; } - /* Setup the flip handler. */ - drm->drm_fds.fd = fd; - drm->drm_fds.events = POLLIN; - drm->drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; - drm->drm_evctx.page_flip_handler = drm_flip_handler; - - drm->drm_fd = fd; - - return drm; + return true; } -static EGLint* gfx_ctx_drm_egl_fill_attribs(GFXContextDRMData* drm, EGLint* attr) +bool EGLDRM::CreateEGLContext(EGLContextData* _egl, const EGLint* egl_attribs) { - *attr++ = EGL_CONTEXT_CLIENT_VERSION; - *attr++ = drm->egl.major ? (EGLint)drm->egl.major : 2; -#ifdef EGL_KHR_create_context - if (drm->egl.minor > 0) - { - *attr++ = EGL_CONTEXT_MINOR_VERSION_KHR; - *attr++ = drm->egl.minor; - } -#endif + EGLContext ctx = eglCreateContext(_egl->dpy, _egl->config, EGL_NO_CONTEXT, egl_attribs); - *attr = EGL_NONE; - return attr; + if (ctx == EGL_NO_CONTEXT) + return false; + + _egl->ctx = ctx; + + return true; } -static bool gbm_choose_xrgb8888_cb(void* display_data, EGLDisplay dpy, EGLConfig config) +bool EGLDRM::CreateEGLSurface(EGLContextData* _egl, void* native_window) { - EGLint r, g, b, id; - (void)display_data; + EGLint window_attribs[] = { + EGL_RENDER_BUFFER, + EGL_BACK_BUFFER, + EGL_NONE, + }; - /* Makes sure we have 8 bit color. */ - if (!eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r)) - return false; - if (!eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g)) - return false; - if (!eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b)) - return false; + _egl->surf = eglCreateWindowSurface(_egl->dpy, _egl->config, (NativeWindowType)native_window, + window_attribs); - if (r != 8 || g != 8 || b != 8) + if (_egl->surf == EGL_NO_SURFACE) return false; - if (!eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &id)) + /* Connect the context to the surface. */ + if (!eglMakeCurrent(_egl->dpy, _egl->surf, _egl->surf, _egl->ctx)) return false; - return id == GBM_FORMAT_XRGB8888; -} - -#define DRM_EGL_ATTRIBS_BASE \ - EGL_SURFACE_TYPE, 0 /*EGL_WINDOW_BIT*/, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, \ - EGL_ALPHA_SIZE, 0, EGL_DEPTH_SIZE, 0 + INFO_LOG(VIDEO, "[EGL]: Current context: %p.\n", (void*)eglGetCurrentContext()); -#ifdef EGL_KHR_create_context -static const EGLint egl_attribs_gles3[] = { - DRM_EGL_ATTRIBS_BASE, - EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES3_BIT_KHR, - EGL_NONE, -}; -#endif + return true; +} -static bool gfx_ctx_drm_egl_set_video_mode(GFXContextDRMData* drm) +bool EGLDRM::SetEGLVideoMode() { const EGLint* attrib_ptr = nullptr; EGLint major; @@ -780,28 +711,28 @@ static bool gfx_ctx_drm_egl_set_video_mode(GFXContextDRMData* drm) attrib_ptr = egl_attribs_gles3; - if (!egl_init_context(&drm->egl, EGL_PLATFORM_GBM_KHR, (EGLNativeDisplayType)drm->gbm_dev, &major, - &minor, &n, attrib_ptr, gbm_choose_xrgb8888_cb)) + if (!InitEGLContext(EGL_PLATFORM_GBM_KHR, (EGLNativeDisplayType)this->m_gbm_dev, &major, &minor, + &n, attrib_ptr, gbm_choose_xrgb8888_cb)) { INFO_LOG(VIDEO, "\n[EGL] Cannot init context error 0x%x", eglGetError()); goto error; } - attr = gfx_ctx_drm_egl_fill_attribs(drm, egl_attribs); + attr = FillDrmEglAttribs(egl_attribs); egl_attribs_ptr = &egl_attribs[0]; - if (!egl_create_context(&drm->egl, (attr != egl_attribs_ptr) ? egl_attribs_ptr : nullptr)) + if (!CreateEGLContext(&this->egl, (attr != egl_attribs_ptr) ? egl_attribs_ptr : nullptr)) { INFO_LOG(VIDEO, "\n[EGL] Cannot create context error 0x%x", eglGetError()); goto error; } - if (!egl_create_surface(&drm->egl, (EGLNativeWindowType)drm->gbm_surface)) + if (!CreateEGLSurface(&this->egl, (EGLNativeWindowType)this->m_gbm_surface)) { INFO_LOG(VIDEO, "\n[EGL] Cannot create context error 0x%x", eglGetError()); return false; } - egl_swap_buffers(&drm->egl); + SwapEglBuffers(); return true; @@ -809,21 +740,17 @@ static bool gfx_ctx_drm_egl_set_video_mode(GFXContextDRMData* drm) return false; } -static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned height, bool fullscreen) +bool EGLDRM::SetVideoMode(unsigned width, unsigned height, bool fullscreen) { int i, ret = 0; struct drm_fb* fb = nullptr; - GFXContextDRMData* drm = (GFXContextDRMData*)data; float video_refresh_rate = (float)VideoInterface::GetTargetRefreshRate(); - if (!drm) - return false; - /* Find desired video mode, and use that. * If not fullscreen, we get desired windowed size, * which is not appropriate. */ if ((width == 0 && height == 0) || !fullscreen) - drm->drm_mode = &drm->drm_connector->modes[0]; + this->m_drm_mode = &this->m_drm_connector->modes[0]; else { /* Try to match refresh_rate as closely as possible. @@ -834,58 +761,58 @@ static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned heig float minimum_fps_diff = 0.0f; /* Find best match. */ - for (i = 0; i < drm->drm_connector->count_modes; i++) + for (i = 0; i < this->m_drm_connector->count_modes; i++) { float diff; - if (width != drm->drm_connector->modes[i].hdisplay || - height != drm->drm_connector->modes[i].vdisplay) + if (width != this->m_drm_connector->modes[i].hdisplay || + height != this->m_drm_connector->modes[i].vdisplay) continue; - diff = fabsf(drm->drm_connector->modes[i].vrefresh - video_refresh_rate); + diff = fabsf(this->m_drm_connector->modes[i].vrefresh - video_refresh_rate); - if (!drm->drm_mode || diff < minimum_fps_diff) + if (!this->m_drm_mode || diff < minimum_fps_diff) { - drm->drm_mode = &drm->drm_connector->modes[i]; + this->m_drm_mode = &this->m_drm_connector->modes[i]; minimum_fps_diff = diff; } } } - if (!drm->drm_mode) + if (!this->m_drm_mode) { INFO_LOG(VIDEO, "[KMS/EGL]: Did not find suitable video mode for %u x %u.\n", width, height); goto error; } - drm->fb_width = drm->drm_mode->hdisplay; - drm->fb_height = drm->drm_mode->vdisplay; + this->m_fb_width = this->m_drm_mode->hdisplay; + this->m_fb_height = this->m_drm_mode->vdisplay; /* Create GBM surface. */ - drm->gbm_surface = - gbm_surface_create(drm->gbm_dev, drm->fb_width, drm->fb_height, GBM_FORMAT_XRGB8888, + this->m_gbm_surface = + gbm_surface_create(this->m_gbm_dev, this->m_fb_width, this->m_fb_height, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - if (!drm->gbm_surface) + if (!this->m_gbm_surface) { INFO_LOG(VIDEO, "[KMS/EGL]: Couldn't create GBM surface.\n"); goto error; } - if (!gfx_ctx_drm_egl_set_video_mode(drm)) + if (!SetEGLVideoMode()) { INFO_LOG(VIDEO, "[KMS/EGL]: Couldn't set EGL video mode.\n"); goto error; } - drm->bo = gbm_surface_lock_front_buffer(drm->gbm_surface); + this->m_bo = gbm_surface_lock_front_buffer(this->m_gbm_surface); - fb = (struct drm_fb*)gbm_bo_get_user_data(drm->bo); + fb = (struct drm_fb*)gbm_bo_get_user_data(this->m_bo); if (!fb) - fb = drm_fb_get_from_bo(drm, drm->bo); + fb = GetFbFromBo(this->m_bo); - ret = drmModeSetCrtc(drm->drm_fd, drm->crtc_id, fb->fb_id, 0, 0, &drm->connector_id, 1, - drm->drm_mode); + ret = drmModeSetCrtc(this->m_drm_fd, this->m_crtc_id, fb->fb_id, 0, 0, &this->m_connector_id, 1, + this->m_drm_mode); if (ret < 0) { INFO_LOG(VIDEO, "[KMS/EGL]: drmModeSetCrtc failed\n"); @@ -894,10 +821,9 @@ static bool gfx_ctx_drm_set_video_mode(void* data, unsigned width, unsigned heig return true; error: - gfx_ctx_drm_destroy_resources(drm); + DestroyResources(); - if (drm) - free(drm); + // TODO destroy ?? return false; } @@ -907,11 +833,12 @@ GLContextEGLDRM::~GLContextEGLDRM() DestroyWindowSurface(); DestroyContext(); - if (!g_drm) - return; - - gfx_ctx_drm_destroy_resources(g_drm); - free(g_drm); + if (g_drm) + { + g_drm->DestroyResources(); + delete g_drm; + } + g_drm = nullptr; } bool GLContextEGLDRM::IsHeadless() const @@ -922,32 +849,13 @@ bool GLContextEGLDRM::IsHeadless() const void GLContextEGLDRM::Swap() { unsigned max_swapchain_images = 2; // double-buffering - - egl_swap_buffers(&g_drm->egl); - - /* I guess we have to wait for flip to have taken - * place before another flip can be queued up. - * - * If true, we are still waiting for a flip - * (nonblocking mode, so just drop the frame). */ - if (gfx_ctx_drm_wait_flip(g_drm, g_drm->interval)) - { - INFO_LOG(VIDEO, "\nwait flip"); - return; - } - - g_drm->waiting_for_flip = gfx_ctx_drm_queue_flip(g_drm); - - /* Triple-buffered page flips */ - if (max_swapchain_images >= 3 && gbm_surface_has_free_buffers(g_drm->gbm_surface)) - return; - - gfx_ctx_drm_wait_flip(g_drm, true); + g_drm->SwapEglBuffers(); + g_drm->SwapDrm(m_interval, max_swapchain_images); } void GLContextEGLDRM::SwapInterval(int interval) { - g_drm->interval = interval; + m_interval = interval; if (interval > 1) INFO_LOG(VIDEO, "[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); @@ -979,16 +887,20 @@ void* GLContextEGLDRM::GetFuncAddress(const std::string& name) // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() bool GLContextEGLDRM::Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) { - g_drm = (GFXContextDRMData*)gfx_ctx_drm_init(); + if (g_drm == nullptr) + g_drm = new EGLDRM(); + if (!g_drm) + return false; + g_drm->Initialize(); eglBindAPI(EGL_OPENGL_ES_API); // Use current video mode, do not switch - gfx_ctx_drm_set_video_mode(g_drm, 0, 0, false); - m_backbuffer_width = g_drm->fb_width; - m_backbuffer_height = g_drm->fb_height; + g_drm->SetVideoMode(0, 0, false); + m_backbuffer_width = g_drm->GetFbWidth(); + m_backbuffer_height = g_drm->GetFbHeight(); - m_egl = &g_drm->egl; + m_egl = &g_drm->GetEGL(); m_opengl_mode = Mode::OpenGLES; m_supports_surfaceless = check_egl_display_extension(m_egl, "EGL_KHR_surfaceless_context"); @@ -1006,7 +918,7 @@ std::unique_ptr GLContextEGLDRM::CreateSharedContext() eglBindAPI(EGL_OPENGL_ES_API); EGLint egl_attribs[16]; EGLint* egl_attribs_ptr = nullptr; - gfx_ctx_drm_egl_fill_attribs(g_drm, egl_attribs); + g_drm->FillDrmEglAttribs(egl_attribs); egl_attribs_ptr = &egl_attribs[0]; new_context->m_egl->ctx = eglCreateContext(m_egl->dpy, m_egl->config, m_egl->ctx, egl_attribs_ptr); @@ -1041,7 +953,7 @@ bool GLContextEGLDRM::CreateWindowSurface() if (!IsHeadless()) { - if (!egl_create_surface(m_egl, (EGLNativeWindowType)g_drm->gbm_surface)) + if (!g_drm->CreateEGLSurface(m_egl, (EGLNativeWindowType)g_drm->GetGbmSurface())) { INFO_LOG(VIDEO, "\negl_create_surface failed (error 0x%x), trying pbuffer instead...\n", eglGetError()); @@ -1084,7 +996,7 @@ void GLContextEGLDRM::DestroyWindowSurface() bool GLContextEGLDRM::MakeCurrent() { - return eglMakeCurrent(m_egl->dpy, g_drm->egl.surf, g_drm->egl.surf, m_egl->ctx); + return eglMakeCurrent(m_egl->dpy, g_drm->GetEGL().surf, g_drm->GetEGL().surf, m_egl->ctx); } void GLContextEGLDRM::UpdateSurface(void* window_handle) diff --git a/Source/Core/Common/GL/GLInterface/EGLDRM.h b/Source/Core/Common/GL/GLInterface/EGLDRM.h index ffa6c7af329e..529e42d1f0aa 100644 --- a/Source/Core/Common/GL/GLInterface/EGLDRM.h +++ b/Source/Core/Common/GL/GLInterface/EGLDRM.h @@ -4,11 +4,34 @@ #pragma once -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + #include "Common/GL/GLContext.h" struct EGLContextData @@ -23,6 +46,68 @@ struct EGLContextData unsigned minor; }; +using EGLAcceptConfigCB = bool (*)(void* display_data, EGLDisplay dpy, EGLConfig config); +using DrmFlipHandler = void (*)(int fd, unsigned frame, unsigned sec, unsigned usec, void* data); +using DrmFbDestroyCB = void (*)(struct gbm_bo* bo, void* data); + +class EGLDRM +{ +public: + EGLDRM() = default; + + bool Initialize(); + bool SetVideoMode(unsigned width, unsigned height, bool fullscreen); + bool QueueFlip(); + EGLint* FillDrmEglAttribs(EGLint* attr); + void SwapEglBuffers(); + void SwapDrm(int interval, int max_swapchain_images); + bool CreateEGLSurface(EGLContextData* egl, void* native_window); // public + void DestroyResources(); + + unsigned GetFbWidth() { return m_fb_width; } + unsigned GetFbHeight() { return m_fb_height; } + int GetDrmFd() { return m_drm_fd; } + struct gbm_surface* GetGbmSurface() { return m_gbm_surface; } + EGLContextData& GetEGL() { return egl; } + +private: + EGLDisplay GetEGLDisplay(EGLenum platform, void* native); + bool InitEGLContext(EGLenum platform, void* display_data, EGLint* major, EGLint* minor, + EGLint* count, const EGLint* attrib_ptr, EGLAcceptConfigCB cb); + bool WaitFlip(bool block); + bool DrmWaitFlip(int timeout); + struct drm_fb* GetFbFromBo(struct gbm_bo* bo); + bool CreateEGLContext(EGLContextData* egl, const EGLint* egl_attribs); + bool SetEGLVideoMode(); + bool GetConnector(int fd); + bool GetEncoder(int fd); + void FreeResources(); + + EGLContextData egl; + + bool m_waiting_for_flip; + struct gbm_bo* m_bo = nullptr; + struct gbm_bo* m_next_bo = nullptr; + struct gbm_surface* m_gbm_surface = nullptr; + struct gbm_device* m_gbm_dev = nullptr; + + drmEventContext m_drm_evctx; + struct pollfd m_drm_fds; + + uint32_t m_fb_width = 0; + uint32_t m_fb_height = 0; + uint32_t m_connector_id = 0; + + int m_fd = -1; + int m_drm_fd = 0; + uint32_t m_crtc_id = 0; + drmModeCrtc* m_orig_crtc = nullptr; + drmModeConnector* m_drm_connector = nullptr; + drmModeModeInfo* m_drm_mode = nullptr; + drmModeRes* m_drm_resources = nullptr; + drmModeEncoder* m_drm_encoder = nullptr; +}; + class GLContextEGLDRM : public GLContext { public: @@ -42,6 +127,8 @@ class GLContextEGLDRM : public GLContext void* GetFuncAddress(const std::string& name) override; + static EGLDRM* GetDrm() { return g_drm; } + protected: bool Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) override; @@ -49,6 +136,8 @@ class GLContextEGLDRM : public GLContext void DestroyWindowSurface(); void DestroyContext(); + static EGLDRM* g_drm; bool m_supports_surfaceless = false; - EGLContextData* m_egl; + EGLContextData* m_egl = nullptr; + int m_interval = 1; }; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index bff3a6422cde..ed8e530b30d9 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -152,6 +152,8 @@ static WindowSystemType GetWindowSystemType() return WindowSystemType::X11; else if (platform_name == QStringLiteral("wayland")) return WindowSystemType::Wayland; + else if (platform_name == QStringLiteral("eglfs")) + return WindowSystemType::DRM; ModalMessageBox::critical( nullptr, QStringLiteral("Error"),