From 6a7d49419cdcb51383403b3640cb92a3b3b36e1d Mon Sep 17 00:00:00 2001 From: Rafael Kitover Date: Mon, 20 Feb 2017 13:20:09 -0800 Subject: [PATCH] initial Wayland support #72 #76 Disable OpenGL support under Wayland because wxGLCanvas segfaults, and fix an issue with drawn frames not appearing. If the user has opengl as the render method in their config, it will not be changed, but at runtime will be set to simple under Wayland. To fix the issue with frames not being drawn, Call Refresh() to queue a PaintEv from DrawArea(data) instead of calling DrawArea(device_context) directly. Also remove the DrawOSD() call from PaintEv, this was causing the OSD to sometimes show up twice in one frame, because DrawArea(data) draws the OSD directly on the frame data. Add new files wayland.cpp and wayland.h with a bool IsItWayland() global function. This uses a GDK (part of GTK) call to detect Wayland. This unfortunately requires linking GTK libs separately. Add cmake code to detect the version of GTK used by the wx being linked and link it as well. Add gtk2 and gtk3 dev packages to the code for the supported linux dists in ./installdeps. --- README.md | 3 +++ installdeps | 6 +++--- src/wx/CMakeLists.txt | 45 +++++++++++++++++++++++++++++++++++++++++++ src/wx/guiinit.cpp | 6 ++++++ src/wx/opts.cpp | 13 +++++-------- src/wx/panel.cpp | 12 ++++++------ src/wx/wayland.cpp | 11 +++++++++++ src/wx/wayland.h | 1 + src/wx/wxvbam.cpp | 9 ++++++++- src/wx/wxvbam.h | 4 ++++ 10 files changed, 92 insertions(+), 18 deletions(-) create mode 100644 src/wx/wayland.cpp create mode 100644 src/wx/wayland.h diff --git a/README.md b/README.md index 90c84d35..71629423 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,9 @@ And the following development libraries: - wxWidgets - cairo (completely optional) +On Linux and similar, you also need the version of GTK your wxWidgets is linked +to (usuall 2 or 3). + Support for more OSes/distributions for `./installdeps` is planned. ## Cross Compiling for Win32 diff --git a/installdeps b/installdeps index a669e372..f8c2efe9 100755 --- a/installdeps +++ b/installdeps @@ -199,7 +199,7 @@ debian_installdeps() { if [ -z "$target" ]; then check sudo apt-get -qq update - check sudo apt-get -qy install build-essential g++ nasm cmake gettext zlib1g-dev libgl1-mesa-dev libavcodec-dev libavformat-dev libswscale-dev libavutil-dev libgettextpo-dev libjpeg-dev libpng-dev libtiff5-dev libsdl2-dev libsfml-dev libopenal-dev libwxgtk3.0-dev + check sudo apt-get -qy install build-essential g++ nasm cmake gettext zlib1g-dev libgl1-mesa-dev libavcodec-dev libavformat-dev libswscale-dev libavutil-dev libgettextpo-dev libjpeg-dev libpng-dev libtiff5-dev libsdl2-dev libsfml-dev libopenal-dev libwxgtk3.0-dev libgtk2.0-dev libgtk-3-dev libcairo2-dev else case "$target" in mingw-w64-i686) @@ -264,7 +264,7 @@ fedora_installdeps() { # this is sometimes necessary for rawhide set -- --exclude='glibc32*' fi - for pkg in zlib-devel mesa-libGL-devel ffmpeg-devel gettext-devel libjpeg-turbo-devel libpng-devel libtiff-devel SDL2-devel SFML-devel openal-soft-devel wxGTK3-devel; do + for pkg in zlib-devel mesa-libGL-devel ffmpeg-devel gettext-devel libjpeg-turbo-devel libpng-devel libtiff-devel SDL2-devel SFML-devel openal-soft-devel wxGTK3-devel gtk2-devel gtk3-devel; do if [ -n "$amd64" ]; then set -- "$@" "${pkg}.x86_64" "${pkg}.i686" else @@ -339,7 +339,7 @@ archlinux_installdeps() { if [ -z "$target" ]; then # native build - check $pacman --noconfirm --needed -S base-devel "$gcc_pkg" nasm zlib mesa cairo cmake ffmpeg gettext libpng libtiff pkg-config sdl2 sfml openal wxgtk + check $pacman --noconfirm --needed -S base-devel "$gcc_pkg" nasm zlib mesa cairo cmake ffmpeg gettext libpng libtiff pkg-config sdl2 sfml openal wxgtk gtk2 gtk3 else # windows cross build case "$target" in diff --git a/src/wx/CMakeLists.txt b/src/wx/CMakeLists.txt index f67cbec6..6578fe89 100644 --- a/src/wx/CMakeLists.txt +++ b/src/wx/CMakeLists.txt @@ -142,6 +142,48 @@ IF(WIN32 AND ENABLE_DIRECTX) FIND_PACKGE ( DirectX REQUIRED ) ENDIF(WIN32 AND ENABLE_DIRECTX) +# we make some direct gtk/gdk calls on linux and such +# so need to link the gtk that wx was built with +IF(NOT WIN32 AND NOT APPLE) + FIND_PATH(WX_CONFIG_H NAMES wx/config.h PATHS ${wxWidgets_INCLUDE_DIRS}) + IF(NOT WX_CONFIG_H) + MESSAGE(FATAL_ERROR "Could not find wx/config.h in ${wxWidgets_INCLUDE_DIRS}") + ENDIF() + SET(WX_CONFIG_H "${WX_CONFIG_H}/wx/config.h") + + INCLUDE(CheckCXXSymbolExists) + CHECK_CXX_SYMBOL_EXISTS(__WXGTK3__ ${WX_CONFIG_H} WX_USING_GTK3) + IF(WX_USING_GTK3) + FIND_PACKAGE(PkgConfig REQUIRED) + PKG_CHECK_MODULES(GTK3 REQUIRED gtk+-3.0) + IF(NOT GTK3_INCLUDE_DIRS) + MESSAGE(FATAL_ERROR "Could not find gtk3") + ENDIF() + INCLUDE_DIRECTORIES(${GTK3_INCLUDE_DIRS}) + LINK_DIRECTORIES(${GTK3_LIBRARY_DIRS}) + ADD_COMPILE_OPTIONS(${GTK3_CFLAGS_OTHER}) + SET(GTK_LIBRARIES ${GTK3_LIBRARIES}) + ELSE() + CHECK_CXX_SYMBOL_EXISTS(__WXGTK20__ ${WX_CONFIG_H} WX_USING_GTK2) + IF(WX_USING_GTK2) + FIND_PACKAGE(GTK2 REQUIRED gtk) + IF(NOT GTK2_INCLUDE_DIRS) + MESSAGE(FATAL_ERROR "Could not find gtk2") + ENDIF() + INCLUDE_DIRECTORIES(${GTK2_INCLUDE_DIRS}) + ADD_COMPILE_OPTIONS(${GTK2_DEFINITIONS}) + SET(GTK_LIBRARIES ${GTK2_LIBRARIES}) + ELSE() + FIND_PACKAGE(GTK REQUIRED gtk) + IF(NOT GTK_INCLUDE_DIRS) + MESSAGE(FATAL_ERROR "Could not find gtk") + ENDIF() + INCLUDE_DIRECTORIES(${GTK_INCLUDE_DIRS}) + ADD_COMPILE_OPTIONS(${GTK_DEFINITIONS}) + ENDIF() + ENDIF() +ENDIF() + # contrib widgets include_directories(widgets) @@ -247,6 +289,7 @@ SET( SRC_WX sys.cpp panel.cpp viewsupt.cpp + wayland.cpp widgets/keyedit.cpp widgets/joyedit.cpp widgets/sdljoy.cpp @@ -278,6 +321,7 @@ SET( HDR_WX opts.h viewsupt.h wxhead.h + wayland.h widgets/wx/keyedit.h widgets/wx/joyedit.h widgets/wx/sdljoy.h @@ -349,6 +393,7 @@ TARGET_LINK_LIBRARIES ( ${FFMPEG_LIBRARIES} ${DIRECTX_LIBRARIES} ${CAIRO_LIBRARIES} + ${GTK_LIBRARIES} ) # Build a console app in debug mode on Windows diff --git a/src/wx/guiinit.cpp b/src/wx/guiinit.cpp index 9fe08f04..41c597eb 100644 --- a/src/wx/guiinit.cpp +++ b/src/wx/guiinit.cpp @@ -3310,6 +3310,12 @@ bool MainFrame::BindControls() getrbi("OutputOpenGL", gopts.render_method, RND_OPENGL); #ifdef NO_OGL rb->Hide(); +#endif +#ifdef __WXGTK__ + // wxGLCanvas segfaults on Wayland + if (wxGetApp().UsingWayland()) { + rb->Hide(); + } #endif getrbi("OutputCairo", gopts.render_method, RND_CAIRO); #ifdef NO_CAIRO diff --git a/src/wx/opts.cpp b/src/wx/opts.cpp index 68198c47..f89e6759 100644 --- a/src/wx/opts.cpp +++ b/src/wx/opts.cpp @@ -279,16 +279,13 @@ opts_t::opts_t() frameSkip = -1; #ifdef __WXMSW__ audio_api = AUD_DIRECTSOUND; -#else -#ifdef __WXMAC__ - audio_api = AUD_OPENAL; +#elif !defined(NO_OAL) && (defined(__WXMAC__) || defined(__WXGTK__)) + audio_api = AUD_OPENAL; +#endif +#ifndef NO_OGL render_method = RND_OPENGL; #endif -#ifdef __WXGTK__ - audio_api = AUD_OPENAL; - render_method = RND_OPENGL; -#endif -#endif + video_scale = 3; retain_aspect = true; max_threads = wxThread::GetCPUCount(); diff --git a/src/wx/panel.cpp b/src/wx/panel.cpp index cb796d9a..a8caeb0b 100644 --- a/src/wx/panel.cpp +++ b/src/wx/panel.cpp @@ -1414,7 +1414,9 @@ void DrawingPanelBase::PaintEv(wxPaintEvent& ev) } DrawArea(dc); - DrawOSD(dc); + + // currently we draw the OSD directly on the framebuffer to reduce flickering + //DrawOSD(dc); } void DrawingPanelBase::EraseBackground(wxEraseEvent& ev) @@ -1794,14 +1796,12 @@ void DrawingPanelBase::DrawArea(uint8_t** data) } } - // next, draw the game - wxClientDC dc(GetWindow()); - DrawArea(dc); + // next, draw the frame (queue a PaintEv) + GetWindow()->Refresh(); // finally, draw on-screen text using wx method, if possible // this method flickers too much right now - if (0) - DrawOSD(dc); + //DrawOSD(dc); } void DrawingPanelBase::DrawOSD(wxWindowDC& dc) diff --git a/src/wx/wayland.cpp b/src/wx/wayland.cpp new file mode 100644 index 00000000..49959833 --- /dev/null +++ b/src/wx/wayland.cpp @@ -0,0 +1,11 @@ +#ifdef __WXGTK__ +#include +#ifdef GDK_WINDOWING_WAYLAND +#include + bool IsItWayland() { return GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default()); } +#else + bool IsItWayland() { return false; } +#endif +#else + bool IsItWayland() { return false; } +#endif diff --git a/src/wx/wayland.h b/src/wx/wayland.h new file mode 100644 index 00000000..29db78d1 --- /dev/null +++ b/src/wx/wayland.h @@ -0,0 +1 @@ +bool IsItWayland(); diff --git a/src/wx/wxvbam.cpp b/src/wx/wxvbam.cpp index fae5fb51..badabd07 100644 --- a/src/wx/wxvbam.cpp +++ b/src/wx/wxvbam.cpp @@ -1,4 +1,3 @@ - // mainline: // parse cmd line // load xrc file (guiinit.cpp does most of instantiation) @@ -21,6 +20,8 @@ #include #include +#include "wayland.h" + // The built-in xrc file #include "builtin-xrc.h" @@ -158,6 +159,7 @@ bool wxvbamApp::OnInit() setvbuf(stderr, NULL, _IONBF, 0); dup2(1, 2); // redirect stderr to stdout #endif + using_wayland = IsItWayland(); // use consistent names for config SetAppName(_("vbam")); @@ -252,6 +254,11 @@ bool wxvbamApp::OnInit() load_opts(); + // wxGLCanvas segfaults under wayland + if (UsingWayland() && gopts.render_method == RND_OPENGL) { + gopts.render_method = RND_SIMPLE; + } + // process command-line options for (int i = 0; i < pending_optset.size(); i++) { wxString p = pending_optset[i]; diff --git a/src/wx/wxvbam.h b/src/wx/wxvbam.h index d2cf5712..d264d396 100644 --- a/src/wx/wxvbam.h +++ b/src/wx/wxvbam.h @@ -79,9 +79,11 @@ public: wxvbamApp() : wxApp() , pending_fullscreen(false) + , using_wayland(false) { } virtual bool OnInit(); + virtual bool UsingWayland() { return using_wayland; } virtual void OnInitCmdLine(wxCmdLineParser&); virtual bool OnCmdLineParsed(wxCmdLineParser&); wxString GetConfigurationPath(); @@ -132,6 +134,8 @@ public: return false; } } +protected: + bool using_wayland; private: wxPathList config_path;