diff --git a/Source/Core/Common/GL/GLContext.cpp b/Source/Core/Common/GL/GLContext.cpp index b02e27778f..5d740f9211 100644 --- a/Source/Core/Common/GL/GLContext.cpp +++ b/Source/Core/Common/GL/GLContext.cpp @@ -30,7 +30,7 @@ const std::array, 9> GLContext::s_desktop_opengl_versions = GLContext::~GLContext() = default; -bool GLContext::Initialize(void* display_handle, void* window_handle, bool stereo, bool core) +bool GLContext::Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) { return false; } @@ -108,7 +108,7 @@ std::unique_ptr GLContext::Create(const WindowSystemInfo& wsi, bool s } #endif #if HAVE_EGL - if (wsi.type == WindowSystemType::Headless) + if (wsi.type == WindowSystemType::Headless || wsi.type == WindowSystemType::FBDev) context = std::make_unique(); #endif @@ -119,7 +119,7 @@ std::unique_ptr GLContext::Create(const WindowSystemInfo& wsi, bool s if (prefer_gles) context->m_opengl_mode = Mode::OpenGLES; - if (!context->Initialize(wsi.display_connection, wsi.render_surface, stereo, core)) + if (!context->Initialize(wsi, stereo, core)) return nullptr; return context; diff --git a/Source/Core/Common/GL/GLContext.h b/Source/Core/Common/GL/GLContext.h index 40cdc776c1..acf2b0d498 100644 --- a/Source/Core/Common/GL/GLContext.h +++ b/Source/Core/Common/GL/GLContext.h @@ -52,7 +52,7 @@ public: bool prefer_gles = false); protected: - virtual bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core); + virtual bool Initialize(const WindowSystemInfo& wsi, bool stereo, bool core); Mode m_opengl_mode = Mode::Detect; diff --git a/Source/Core/Common/GL/GLInterface/AGL.h b/Source/Core/Common/GL/GLInterface/AGL.h index 59d0116954..477aa72efd 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.h +++ b/Source/Core/Common/GL/GLInterface/AGL.h @@ -32,7 +32,7 @@ public: void SwapInterval(int interval) override; protected: - bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override; + bool Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) override; NSView* m_view = nullptr; NSOpenGLContext* m_context = nullptr; diff --git a/Source/Core/Common/GL/GLInterface/AGL.mm b/Source/Core/Common/GL/GLInterface/AGL.mm index e10e52b311..ec58625dac 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.mm +++ b/Source/Core/Common/GL/GLInterface/AGL.mm @@ -69,7 +69,7 @@ void GLContextAGL::Swap() // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool GLContextAGL::Initialize(void* display_handle, void* window_handle, bool stereo, bool core) +bool GLContextAGL::Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) { NSOpenGLPixelFormatAttribute attr[] = { NSOpenGLPFADoubleBuffer, @@ -92,10 +92,10 @@ bool GLContextAGL::Initialize(void* display_handle, void* window_handle, bool st return false; } - if (!window_handle) + if (!wsi.render_surface) return true; - m_view = static_cast(window_handle); + m_view = static_cast(wsi.render_surface); m_opengl_mode = Mode::OpenGL; if (!AttachContextToView(m_context, m_view, &m_backbuffer_width, &m_backbuffer_height)) return false; diff --git a/Source/Core/Common/GL/GLInterface/EGL.cpp b/Source/Core/Common/GL/GLInterface/EGL.cpp index 93a60ca9d8..6163754095 100644 --- a/Source/Core/Common/GL/GLInterface/EGL.cpp +++ b/Source/Core/Common/GL/GLInterface/EGL.cpp @@ -35,7 +35,7 @@ GLContextEGL::~GLContextEGL() bool GLContextEGL::IsHeadless() const { - return m_host_window == nullptr; + return m_wsi.type == WindowSystemType::Headless; } void GLContextEGL::Swap() @@ -53,7 +53,7 @@ void* GLContextEGL::GetFuncAddress(const std::string& name) return (void*)eglGetProcAddress(name.c_str()); } -void GLContextEGL::DetectMode(bool has_handle) +void GLContextEGL::DetectMode() { EGLint num_configs; bool supportsGL = false, supportsGLES3 = false; @@ -72,7 +72,7 @@ void GLContextEGL::DetectMode(bool has_handle) EGL_RENDERABLE_TYPE, renderable_type, EGL_SURFACE_TYPE, - has_handle ? EGL_WINDOW_BIT : 0, + IsHeadless() ? 0 : EGL_WINDOW_BIT, EGL_NONE}; // Get how many configs there are @@ -130,27 +130,23 @@ void GLContextEGL::DetectMode(bool has_handle) EGLDisplay GLContextEGL::OpenEGLDisplay() { - return eglGetDisplay(EGL_DEFAULT_DISPLAY); + return eglGetDisplay(static_cast(m_wsi.render_surface)); } EGLNativeWindowType GLContextEGL::GetEGLNativeWindow(EGLConfig config) { - return reinterpret_cast(EGL_DEFAULT_DISPLAY); + return reinterpret_cast(m_wsi.display_connection); } // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool GLContextEGL::Initialize(void* display_handle, void* window_handle, bool stereo, bool core) +bool GLContextEGL::Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) { - const bool has_handle = !!window_handle; - EGLint egl_major, egl_minor; bool supports_core_profile = false; - m_host_display = display_handle; - m_host_window = window_handle; + m_wsi = wsi; m_egl_display = OpenEGLDisplay(); - if (!m_egl_display) { INFO_LOG(VIDEO, "Error: eglGetDisplay() failed"); @@ -167,7 +163,7 @@ bool GLContextEGL::Initialize(void* display_handle, void* window_handle, bool st EGLint num_configs; if (m_opengl_mode == Mode::Detect) - DetectMode(has_handle); + DetectMode(); // attributes for a visual in RGBA format with at least // 8 bits per color @@ -180,7 +176,7 @@ bool GLContextEGL::Initialize(void* display_handle, void* window_handle, bool st EGL_BLUE_SIZE, 8, EGL_SURFACE_TYPE, - has_handle ? EGL_WINDOW_BIT : 0, + IsHeadless() ? 0 : EGL_WINDOW_BIT, EGL_NONE}; std::vector ctx_attribs; @@ -278,7 +274,7 @@ std::unique_ptr GLContextEGL::CreateSharedContext() std::unique_ptr new_context = std::make_unique(); new_context->m_opengl_mode = m_opengl_mode; new_context->m_egl_context = new_egl_context; - new_context->m_host_display = m_host_display; + new_context->m_wsi.display_connection = m_wsi.display_connection; new_context->m_egl_display = m_egl_display; new_context->m_config = m_config; new_context->m_supports_surfaceless = m_supports_surfaceless; @@ -294,7 +290,7 @@ std::unique_ptr GLContextEGL::CreateSharedContext() bool GLContextEGL::CreateWindowSurface() { - if (m_host_window) + if (!IsHeadless()) { EGLNativeWindowType native_window = GetEGLNativeWindow(m_config); m_egl_surface = eglCreateWindowSurface(m_egl_display, m_config, native_window, nullptr); @@ -303,6 +299,17 @@ bool GLContextEGL::CreateWindowSurface() INFO_LOG(VIDEO, "Error: eglCreateWindowSurface failed"); return false; } + + // Get dimensions from the surface. + EGLint surface_width = 1, surface_height = 1; + if (!eglQuerySurface(m_egl_display, m_egl_surface, EGL_WIDTH, &surface_width) || + !eglQuerySurface(m_egl_display, m_egl_surface, EGL_HEIGHT, &surface_height)) + { + WARN_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); } else if (!m_supports_surfaceless) { @@ -342,7 +349,7 @@ bool GLContextEGL::MakeCurrent() void GLContextEGL::UpdateSurface(void* window_handle) { - m_host_window = window_handle; + m_wsi.render_surface = window_handle; ClearCurrent(); DestroyWindowSurface(); CreateWindowSurface(); diff --git a/Source/Core/Common/GL/GLInterface/EGL.h b/Source/Core/Common/GL/GLInterface/EGL.h index 51dd3fda35..62fe6f785e 100644 --- a/Source/Core/Common/GL/GLInterface/EGL.h +++ b/Source/Core/Common/GL/GLInterface/EGL.h @@ -34,15 +34,14 @@ protected: virtual EGLDisplay OpenEGLDisplay(); virtual EGLNativeWindowType GetEGLNativeWindow(EGLConfig config); - bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override; + bool Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) override; bool CreateWindowSurface(); void DestroyWindowSurface(); - void DetectMode(bool has_handle); + void DetectMode(); void DestroyContext(); - void* m_host_display = nullptr; - void* m_host_window = nullptr; + WindowSystemInfo m_wsi = {}; EGLConfig m_config; bool m_supports_surfaceless = false; diff --git a/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp b/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp index 2a5123b21f..66639c7614 100644 --- a/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp @@ -14,8 +14,8 @@ EGLNativeWindowType GLContextEGLAndroid::GetEGLNativeWindow(EGLConfig config) { EGLint format; eglGetConfigAttrib(m_egl_display, config, EGL_NATIVE_VISUAL_ID, &format); - ANativeWindow_setBuffersGeometry(static_cast(m_host_window), 0, 0, format); - m_backbuffer_width = ANativeWindow_getWidth(static_cast(m_host_window)); - m_backbuffer_height = ANativeWindow_getHeight(static_cast(m_host_window)); - return static_cast(m_host_window); + ANativeWindow_setBuffersGeometry(static_cast(m_wsi.render_surface), 0, 0, format); + m_backbuffer_width = ANativeWindow_getWidth(static_cast(m_wsi.render_surface)); + m_backbuffer_height = ANativeWindow_getHeight(static_cast(m_wsi.render_surface)); + return static_cast(m_wsi.render_surface); } diff --git a/Source/Core/Common/GL/GLInterface/EGLX11.cpp b/Source/Core/Common/GL/GLInterface/EGLX11.cpp index bd59033738..3c5ef2c87e 100644 --- a/Source/Core/Common/GL/GLInterface/EGLX11.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLX11.cpp @@ -21,7 +21,7 @@ void GLContextEGLX11::Update() EGLDisplay GLContextEGLX11::OpenEGLDisplay() { - return eglGetDisplay(static_cast(m_host_display)); + return eglGetDisplay(static_cast(m_wsi.display_connection)); } EGLNativeWindowType GLContextEGLX11::GetEGLNativeWindow(EGLConfig config) @@ -33,14 +33,14 @@ EGLNativeWindowType GLContextEGLX11::GetEGLNativeWindow(EGLConfig config) visTemplate.visualid = vid; int nVisuals; - XVisualInfo* vi = - XGetVisualInfo(static_cast(m_host_display), VisualIDMask, &visTemplate, &nVisuals); + XVisualInfo* vi = XGetVisualInfo(static_cast(m_wsi.display_connection), VisualIDMask, + &visTemplate, &nVisuals); if (m_render_window) m_render_window.reset(); - m_render_window = GLX11Window::Create(static_cast(m_host_display), - reinterpret_cast(m_host_window), vi); + m_render_window = GLX11Window::Create(static_cast(m_wsi.display_connection), + reinterpret_cast(m_wsi.render_surface), vi); m_backbuffer_width = m_render_window->GetWidth(); m_backbuffer_height = m_render_window->GetHeight(); diff --git a/Source/Core/Common/GL/GLInterface/GLX.cpp b/Source/Core/Common/GL/GLInterface/GLX.cpp index 78814db80f..70ee8485b2 100644 --- a/Source/Core/Common/GL/GLInterface/GLX.cpp +++ b/Source/Core/Common/GL/GLInterface/GLX.cpp @@ -73,9 +73,9 @@ void GLContextGLX::Swap() // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool GLContextGLX::Initialize(void* display_handle, void* window_handle, bool stereo, bool core) +bool GLContextGLX::Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) { - m_display = static_cast(display_handle); + m_display = static_cast(wsi.display_connection); int screen = DefaultScreen(m_display); // checking glx version @@ -204,7 +204,7 @@ bool GLContextGLX::Initialize(void* display_handle, void* window_handle, bool st } } - if (!CreateWindowSurface(reinterpret_cast(window_handle))) + if (!CreateWindowSurface(reinterpret_cast(wsi.render_surface))) { ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed\n"); XSetErrorHandler(oldHandler); diff --git a/Source/Core/Common/GL/GLInterface/GLX.h b/Source/Core/Common/GL/GLInterface/GLX.h index 1b74e53f60..6ce2c21aae 100644 --- a/Source/Core/Common/GL/GLInterface/GLX.h +++ b/Source/Core/Common/GL/GLInterface/GLX.h @@ -33,7 +33,7 @@ public: void* GetFuncAddress(const std::string& name) override; protected: - bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override; + bool Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) override; Display* m_display = nullptr; std::unique_ptr m_render_window; diff --git a/Source/Core/Common/GL/GLInterface/WGL.cpp b/Source/Core/Common/GL/GLInterface/WGL.cpp index e168f94e51..034d05a415 100644 --- a/Source/Core/Common/GL/GLInterface/WGL.cpp +++ b/Source/Core/Common/GL/GLInterface/WGL.cpp @@ -223,13 +223,13 @@ void* GLContextWGL::GetFuncAddress(const std::string& name) // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool GLContextWGL::Initialize(void* display_handle, void* window_handle, bool stereo, bool core) +bool GLContextWGL::Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) { - if (!window_handle) + if (!wsi.render_surface) return false; RECT window_rect = {}; - m_window_handle = reinterpret_cast(window_handle); + m_window_handle = reinterpret_cast(wsi.render_surface); if (!GetClientRect(m_window_handle, &window_rect)) return false; diff --git a/Source/Core/Common/GL/GLInterface/WGL.h b/Source/Core/Common/GL/GLInterface/WGL.h index 9e3f9d86ef..11ed8d8861 100644 --- a/Source/Core/Common/GL/GLInterface/WGL.h +++ b/Source/Core/Common/GL/GLInterface/WGL.h @@ -28,7 +28,7 @@ public: void* GetFuncAddress(const std::string& name) override; protected: - bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override; + bool Initialize(const WindowSystemInfo& wsi, bool stereo, bool core) override; static HGLRC CreateCoreContext(HDC dc, HGLRC share_context); static bool CreatePBuffer(HDC onscreen_dc, int width, int height, HANDLE* pbuffer_handle, diff --git a/Source/Core/Common/WindowSystemInfo.h b/Source/Core/Common/WindowSystemInfo.h index bea853d445..03f230f8e6 100644 --- a/Source/Core/Common/WindowSystemInfo.h +++ b/Source/Core/Common/WindowSystemInfo.h @@ -11,7 +11,8 @@ enum class WindowSystemType MacOS, Android, X11, - Wayland + Wayland, + FBDev, }; struct WindowSystemInfo diff --git a/Source/Core/DolphinNoGUI/CMakeLists.txt b/Source/Core/DolphinNoGUI/CMakeLists.txt index 0b54022594..6247dac2d0 100644 --- a/Source/Core/DolphinNoGUI/CMakeLists.txt +++ b/Source/Core/DolphinNoGUI/CMakeLists.txt @@ -9,6 +9,10 @@ if(ENABLE_X11 AND X11_FOUND) target_sources(dolphin-nogui PRIVATE PlatformX11.cpp) endif() +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + target_sources(dolphin-nogui PRIVATE PlatformFBDev.cpp) +endif() + set_target_properties(dolphin-nogui PROPERTIES OUTPUT_NAME dolphin-emu-nogui) target_link_libraries(dolphin-nogui diff --git a/Source/Core/DolphinNoGUI/MainNoGUI.cpp b/Source/Core/DolphinNoGUI/MainNoGUI.cpp index 711583f736..1736c52edd 100644 --- a/Source/Core/DolphinNoGUI/MainNoGUI.cpp +++ b/Source/Core/DolphinNoGUI/MainNoGUI.cpp @@ -121,6 +121,11 @@ static std::unique_ptr GetPlatform(const optparse::Values& options) return Platform::CreateX11Platform(); #endif +#ifdef __linux__ + if (platform_name == "fbdev" || platform_name.empty()) + return Platform::CreateFBDevPlatform(); +#endif + if (platform_name == "headless" || platform_name.empty()) return Platform::CreateHeadlessPlatform(); @@ -135,6 +140,10 @@ int main(int argc, char* argv[]) .help("Window platform to use [%choices]") .choices({ "headless" +#ifdef __linux__ + , + "fbdev" +#endif #if HAVE_X11 , "x11" diff --git a/Source/Core/DolphinNoGUI/Platform.h b/Source/Core/DolphinNoGUI/Platform.h index 19edbb1168..af39492447 100644 --- a/Source/Core/DolphinNoGUI/Platform.h +++ b/Source/Core/DolphinNoGUI/Platform.h @@ -35,6 +35,9 @@ public: #ifdef HAVE_X11 static std::unique_ptr CreateX11Platform(); #endif +#ifdef __linux__ + static std::unique_ptr CreateFBDevPlatform(); +#endif protected: void UpdateRunningFlag(); diff --git a/Source/Core/DolphinNoGUI/PlatformFBDev.cpp b/Source/Core/DolphinNoGUI/PlatformFBDev.cpp new file mode 100644 index 0000000000..9818105521 --- /dev/null +++ b/Source/Core/DolphinNoGUI/PlatformFBDev.cpp @@ -0,0 +1,102 @@ +// Copyright 2018 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 PlatformFBDev : public Platform +{ +public: + ~PlatformFBDev() override; + + bool Init() override; + void SetTitle(const std::string& string) override; + void MainLoop() override; + + WindowSystemInfo GetWindowSystemInfo() const; + +private: + bool OpenFramebuffer(); + + int m_fb_fd = -1; +}; + +PlatformFBDev::~PlatformFBDev() +{ + if (m_fb_fd >= 0) + close(m_fb_fd); +} + +bool PlatformFBDev::Init() +{ + if (!OpenFramebuffer()) + return false; + + return true; +} + +bool PlatformFBDev::OpenFramebuffer() +{ + m_fb_fd = open("/dev/fb0", O_RDWR); + if (m_fb_fd < 0) + { + std::fprintf(stderr, "open(/dev/fb0) failed\n"); + return false; + } + + return true; +} + +void PlatformFBDev::SetTitle(const std::string& string) +{ + std::fprintf(stdout, "%s\n", string.c_str()); +} + +void PlatformFBDev::MainLoop() +{ + while (IsRunning()) + { + UpdateRunningFlag(); + Core::HostDispatchJobs(); + + // TODO: Is this sleep appropriate? + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } +} + +WindowSystemInfo PlatformFBDev::GetWindowSystemInfo() const +{ + WindowSystemInfo wsi; + wsi.type = WindowSystemType::FBDev; + wsi.display_connection = nullptr; // EGL_DEFAULT_DISPLAY + wsi.render_surface = nullptr; + return wsi; +} +} // namespace + +std::unique_ptr Platform::CreateFBDevPlatform() +{ + return std::make_unique(); +}