diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index ac7899b7c35..690cc99838b 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -107,8 +107,13 @@ jobs: custombuild: runs-on: ubuntu-20.04 steps: + - name: Install Dependencies + run: | + sudo apt update + sudo apt install -y libwayland-dev libwayland-egl1 pkg-config libegl-dev \ + qtwayland5 qtbase5-private-dev - uses: actions/checkout@v4 - name: Build run: | - cmake -Bbuild -DOGRE_BUILD_DEPENDENCIES=OFF -DSWIG_EXECUTABLE=none -DOGRE_CONFIG_DOUBLE=ON -DOGRE_ASSERT_MODE=1 -DOGRE_PROFILING=ON . - cmake --build build -- -j 4 \ No newline at end of file + cmake -Bbuild -DOGRE_BUILD_DEPENDENCIES=OFF -DSWIG_EXECUTABLE=none -DOGRE_CONFIG_DOUBLE=ON -DOGRE_ASSERT_MODE=1 -DOGRE_PROFILING=ON -DOGRE_GLSUPPORT_USE_WAYLAND=ON . + cmake --build build -- -j 4 diff --git a/BuildingOgre.md b/BuildingOgre.md index a421f470db0..bea4640ede7 100644 --- a/BuildingOgre.md +++ b/BuildingOgre.md @@ -42,25 +42,36 @@ For manually building the dependencies, please refer to the list below and get a ### Linux On linux you additionally need the following system headers to build the GL, GL3+, GLES2 & Vulkan RenderSystems: + * Ubuntu - sudo apt-get install libgles2-mesa-dev libvulkan-dev glslang-dev libxrandr-dev + sudo apt-get install libgles2-mesa-dev libvulkan-dev glslang-dev + + * **X11**: `sudo apt-get install libxrandr-dev` + * **Wayland**: `sudo apt-get install pkg-config libwayland-dev libwayland-egl1 libegl-dev` * Fedora - sudo dnf install mesa-libGL-devel mesa-vulkan-devel glslang-devel + sudo dnf install mesa-libGL-devel mesa-libEGL-devel mesa-vulkan-devel glslang-devel + + * **X11**: `sudo dnf install libXrandr-devel` + * **Wayland**: `sudo dnv install pkgconfig wayland-devel egl-wayland` -furthermore we recommend installing the following optional packages +Furthermore, we recommend installing the following optional packages * Ubuntu - sudo apt-get install libsdl2-dev libxt-dev libxaw7-dev doxygen + sudo apt-get install libsdl2-dev doxygen + + * **X11**: `sudo apt-get install libxt-dev libxaw7-dev` * Fedora - sudo dnf install SDL2-devel libXt-devel libXaw-devel doxygen pugixml-devel + sudo dnf install SDL2-devel doxygen + + * **X11**: `sudo dnf install libXt-devel libXaw-devel` -these will enable input handling in the SampleBrowser, the X11 ConfigDialog and allow building the documentation. +These will enable input handling in the SampleBrowser, the X11 ConfigDialog and allow building the documentation. ### Recommended dependencies @@ -79,6 +90,7 @@ these will enable input handling in the SampleBrowser, the X11 ConfigDialog and * Remotery: https://github.com/Celtoys/Remotery * SWIG: http://www.swig.org/ * %Assimp: https://www.assimp.org/ +* Wayland: https://wayland.freedesktop.org/ Running CMake ------------- @@ -106,6 +118,7 @@ particular component/ plugin from being built - `OGRE_ASSERT_MODE` allows you to to disable all runtime assertion exceptions or turn them into calls to `std::abort`. - `OGRE_RESOURCEMANGER_STRICT` allows you to turn on resource lookup related quirks for pre ogre 1.10 compatibility. - `OGRE_NODELESS_POSITIONING` allows to use Lights and Cameras without attaching them to nodes (only for legacy code). +- `OGRE_GLSUPPORT_USE_WAYLAND` will use Wayland window system instead of X11 on Linux for GL-based RenderSystems. Once you are satisfied, hit *Configure* again and then click on *Generate*. CMake will then create diff --git a/CMake/Dependencies.cmake b/CMake/Dependencies.cmake index 2dc995c5a1d..9ab5869d297 100644 --- a/CMake/Dependencies.cmake +++ b/CMake/Dependencies.cmake @@ -219,8 +219,19 @@ macro_log_feature(FREETYPE_FOUND "freetype" "Portable font engine" "http://www.f # Find X11 if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT EMSCRIPTEN) - find_package(X11 REQUIRED) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(waylands IMPORTED_TARGET wayland-client wayland-egl egl) + macro_log_feature(waylands_FOUND "Wayland" "Wayland window system" "https://wayland.freedesktop.org") + endif () + + if (NOT waylands_FOUND) + find_package(X11 REQUIRED) + else () + find_package(X11) + endif () macro_log_feature(X11_FOUND "X11" "X Window system" "http://www.x.org") + endif () diff --git a/CMake/Templates/OGREStatic.pc.in b/CMake/Templates/OGREStatic.pc.in index 4e4202bb8b5..ff3c7c82ff1 100644 --- a/CMake/Templates/OGREStatic.pc.in +++ b/CMake/Templates/OGREStatic.pc.in @@ -8,6 +8,6 @@ Name: OGRE (static lib) Description: Object-Oriented Graphics Rendering Engine Version: @OGRE_VERSION@ URL: http://www.ogre3d.org -Requires: freetype2, zziplib, x11, xt, xaw7, gl +Requires: freetype2, zziplib, gl, x11, xt, xaw7, wayland Libs: -L${libdir} -L${plugindir} -lOgreMain@OGRE_LIB_SUFFIX@ @OGRE_ADDITIONAL_LIBS@ Cflags: -I${includedir} -I${includedir}/OGRE @OGRE_CFLAGS@ diff --git a/Components/Bites/CMakeLists.txt b/Components/Bites/CMakeLists.txt index aed3428c3ac..58b5b138bbb 100644 --- a/Components/Bites/CMakeLists.txt +++ b/Components/Bites/CMakeLists.txt @@ -108,7 +108,7 @@ elseif(ANDROID) endif() cmake_dependent_option(OGRE_BITES_NATIVE_DIALOG "Provide a platform specific ConfigDialog implementation" - ON "NOT ANDROID;NOT EMSCRIPTEN;NOT APPLE_IOS;NOT WINDOWS_STORE;NOT WINDOWS_PHONE;NOT UNIX OR APPLE OR XAW_LIBRARY" OFF) + ON "NOT OGRE_GLSUPPORT_USE_WAYLAND;NOT ANDROID;NOT EMSCRIPTEN;NOT APPLE_IOS;NOT WINDOWS_STORE;NOT WINDOWS_PHONE;NOT UNIX OR APPLE OR XAW_LIBRARY" OFF) if(NOT OGRE_BITES_NATIVE_DIALOG) set_source_files_properties(src/OgreBitesConfigDialog.cpp PROPERTIES COMPILE_DEFINITIONS DISABLE_NATIVE_DIALOG) @@ -134,14 +134,13 @@ elseif(APPLE) set(RESOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/misc/ogrelogo.png") source_group(Resources FILES ${RESOURCE_FILES}) set(DEPENDENCIES ${DEPENDENCIES} "-framework Cocoa") -elseif(UNIX AND XAW_LIBRARY) +elseif(UNIX AND XAW_LIBRARY AND NOT OGRE_GLSUPPORT_USE_WAYLAND) list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/OgreGLXConfigDialog.cpp") list(APPEND DEPENDENCIES ${X11_Xt_LIB} ${XAW_LIBRARY}) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/misc/GLX_backdrop.png" DESTINATION "${OGRE_MEDIA_PATH}/../") endif() -if(UNIX AND NOT APPLE) - # for WindowEventUtilities +if(UNIX AND NOT APPLE AND NOT OGRE_GLSUPPORT_USE_WAYLAND) list(APPEND DEPENDENCIES ${X11_X11_LIB}) set(NATIVE_INCLUDES ${X11_Xlib_INCLUDE_PATH}) endif() @@ -176,6 +175,10 @@ if(OGRE_STATIC AND APPLE AND OGRE_BUILD_PLUGIN_CG) target_include_directories(OgreBites PUBLIC ${Cg_INCLUDE_DIRS}) endif() +if(OGRE_GLSUPPORT_USE_WAYLAND) + target_compile_definitions(OgreBites PRIVATE OGRE_WAYLAND) +endif() + if(SDL2_FOUND) target_link_libraries(OgreBites PRIVATE SDL2::SDL2) elseif(NOT EMSCRIPTEN) @@ -187,6 +190,21 @@ generate_export_header(OgreBites EXPORT_FILE_NAME ${PROJECT_BINARY_DIR}/include/OgreBitesPrerequisites.h) if(Qt6_FOUND OR Qt5_FOUND) + set(_OgreBitesQt ON) +else() + set(_OgreBitesQt OFF) +endif() + +if(OGRE_GLSUPPORT_USE_WAYLAND) + if(NOT TARGET Qt${QT_VERSION_MAJOR}::GuiPrivate) + set(_OgreBitesQt OFF) + else() + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/include/OgreQtNativeinterface.h.in" + "${PROJECT_BINARY_DIR}/include_private/OgreQtNativeinterface.h" @ONLY) + endif() +endif() + +if(_OgreBitesQt) if(Qt6_FOUND) qt6_wrap_cpp(MOC_SRC "${CMAKE_CURRENT_SOURCE_DIR}/include/OgreApplicationContextQt.h") else() @@ -196,10 +214,16 @@ if(Qt6_FOUND OR Qt5_FOUND) add_library(OgreBitesQt ${OGRE_COMP_LIB_TYPE} ${MOC_SRC} "${CMAKE_CURRENT_SOURCE_DIR}/src/OgreApplicationContextQt.cpp") set_target_properties(OgreBitesQt PROPERTIES VERSION ${OGRE_SOVERSION} SOVERSION ${OGRE_SOVERSION}) target_link_libraries(OgreBitesQt PUBLIC Qt${QT_VERSION_MAJOR}::Gui OgreBites) + if(OGRE_GLSUPPORT_USE_WAYLAND) + target_compile_definitions(OgreBitesQt PRIVATE OGRE_WAYLAND) + target_link_libraries(OgreBitesQt PRIVATE Qt${QT_VERSION_MAJOR}::GuiPrivate) + target_include_directories(OgreBitesQt PRIVATE + "$") + endif() ogre_config_component(OgreBitesQt) endif() -# install +# install ogre_config_framework(OgreBites) ogre_config_component(OgreBites) diff --git a/Components/Bites/include/OgreQtNativeinterface.h.in b/Components/Bites/include/OgreQtNativeinterface.h.in new file mode 100644 index 00000000000..0f45359f42d --- /dev/null +++ b/Components/Bites/include/OgreQtNativeinterface.h.in @@ -0,0 +1,2 @@ +#pragma once +#include <@QT_VERSION@/QtGui/qpa/qplatformnativeinterface.h> diff --git a/Components/Bites/src/OgreApplicationContextQt.cpp b/Components/Bites/src/OgreApplicationContextQt.cpp index 45c0fe87218..85ac1e3ec2b 100644 --- a/Components/Bites/src/OgreApplicationContextQt.cpp +++ b/Components/Bites/src/OgreApplicationContextQt.cpp @@ -16,6 +16,10 @@ #include #include +#ifdef OGRE_WAYLAND +#include "OgreQtNativeinterface.h" +#endif + namespace OgreBites { static Event convert(const QEvent* in) @@ -129,8 +133,29 @@ namespace OgreBites p.width = window->width(); p.height= window->height(); - p.miscParams["externalWindowHandle"] = std::to_string(size_t(window->winId())); + if (QGuiApplication::platformName() != "wayland") { + p.miscParams["externalWindowHandle"] = std::to_string(size_t(window->winId())); + } + + if (QGuiApplication::platformName() == "wayland") + { + window->create(); // This must be called since window->winId() is not called. + +#ifdef OGRE_WAYLAND + QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); + if (!nativeInterface) + { + Ogre::LogManager::getSingleton().logMessage("[Qt] Native interface is nullptr!"); + } + + void* display = nativeInterface->nativeResourceForWindow("display", nullptr); + void* surface = nativeInterface->nativeResourceForWindow("surface", window); + + p.miscParams["externalWlDisplay"] = Ogre::StringConverter::toString(size_t(display)); + p.miscParams["externalWlSurface"] = Ogre::StringConverter::toString(size_t(surface)); +#endif + } if (!mWindows.empty()) { // additional windows should reuse the context diff --git a/Components/Bites/src/OgreApplicationContextSDL.cpp b/Components/Bites/src/OgreApplicationContextSDL.cpp index 78dcd292915..05ed4a80e73 100644 --- a/Components/Bites/src/OgreApplicationContextSDL.cpp +++ b/Components/Bites/src/OgreApplicationContextSDL.cpp @@ -68,7 +68,17 @@ NativeWindowPair ApplicationContextSDL::createWindow(const Ogre::String& name, O p.miscParams["sdlwin"] = Ogre::StringConverter::toString(size_t(ret.native)); #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - p.miscParams["externalWindowHandle"] = Ogre::StringConverter::toString(size_t(wmInfo.info.x11.window)); + if (wmInfo.subsystem == SDL_SYSWM_WAYLAND) + { + Ogre::LogManager::getSingleton().logMessage("[SDL] Creating Wayland window"); + p.miscParams["externalWlDisplay"] = Ogre::StringConverter::toString(size_t(wmInfo.info.wl.display)); + p.miscParams["externalWlSurface"] = Ogre::StringConverter::toString(size_t(wmInfo.info.wl.surface)); + } + else if (wmInfo.subsystem == SDL_SYSWM_X11) + { + Ogre::LogManager::getSingleton().logMessage("[SDL] Creating X11 window"); + p.miscParams["externalWindowHandle"] = Ogre::StringConverter::toString(size_t(wmInfo.info.x11.window)); + } #elif OGRE_PLATFORM == OGRE_PLATFORM_WIN32 p.miscParams["externalWindowHandle"] = Ogre::StringConverter::toString(size_t(wmInfo.info.win.window)); #elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE diff --git a/Components/Bites/src/OgreWindowEventUtilities.cpp b/Components/Bites/src/OgreWindowEventUtilities.cpp index 507c65c10f9..87b0ede7bd5 100644 --- a/Components/Bites/src/OgreWindowEventUtilities.cpp +++ b/Components/Bites/src/OgreWindowEventUtilities.cpp @@ -36,8 +36,8 @@ THE SOFTWARE. # define NOMINMAX // required to stop windows.h messing up std::min # endif # include -#elif OGRE_PLATFORM == OGRE_PLATFORM_LINUX -#include +#elif OGRE_PLATFORM == OGRE_PLATFORM_LINUX && !defined(OGRE_WAYLAND) +# include #endif using namespace Ogre; @@ -47,7 +47,7 @@ typedef std::multimap WindowEventListeners; static WindowEventListeners _msListeners; static RenderWindowList _msWindows; -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX && !defined(OGRE_WAYLAND) static void GLXProc( RenderWindow *win, const XEvent &event ); #endif @@ -184,7 +184,7 @@ void WindowEventUtilities::messagePump() TranslateMessage( &msg ); DispatchMessage( &msg ); } -#elif OGRE_PLATFORM == OGRE_PLATFORM_LINUX +#elif OGRE_PLATFORM == OGRE_PLATFORM_LINUX && !defined(OGRE_WAYLAND) //GLX Message Pump Display* xDisplay = 0; // same for all windows @@ -240,7 +240,7 @@ void WindowEventUtilities::_removeRenderWindow(RenderWindow* window) _msWindows.erase( i ); } -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX && !defined(OGRE_WAYLAND) //--------------------------------------------------------------------------------// static void GLXProc( Ogre::RenderWindow *win, const XEvent &event ) { diff --git a/OgreMain/include/OgreRenderSystem.h b/OgreMain/include/OgreRenderSystem.h index 3dd1a346f71..f5fc1b25cdc 100644 --- a/OgreMain/include/OgreRenderSystem.h +++ b/OgreMain/include/OgreRenderSystem.h @@ -385,6 +385,8 @@ namespace Ogre | displayFrequency | Refresh rate in Hertz (e.g. 60, 75, 100) | Desktop vsync rate | Display frequency rate, for fullscreen mode | | | externalWindowHandle |
  • Win32: HWND as int
  • Linux: X11 Window as ulong
  • OSX: OgreGLView address as an integer. You can pass NSView or NSWindow too, but should perform OgreGLView callbacks into the Ogre manually
  • iOS: UIWindow address as an integer
  • Emscripten: canvas selector String ("#canvas")
| 0 (none) | External window handle, for embedding the OGRE render in an existing window | | | externalGLControl | true, false | false | Let the external window control OpenGL i.e. don't select a pixel format for the window, do not change v-sync and do not swap buffer. When set to true, the calling application is responsible of OpenGL initialization and buffer swapping. It should also create an OpenGL context for its own rendering, Ogre will create one for its use. Then the calling application must also enable Ogre OpenGL context before calling any Ogre function and restore its OpenGL context after these calls. | OpenGL | + | externalWlDisplay | wl_display address as an integer | 0 (none) | Wayland display connection | Linux | + | externalWlSurface | wl_surface address as an integer | 0 (none) | Wayland onscreen surface | Linux | | currentGLContext | true, false | false | Use an externally created GL context. (Must be current) | OpenGL | | minColourBufferSize | Positive integer (usually 16, 32) | 16 | Min total colour buffer size. See EGL_BUFFER_SIZE | OpenGL | | windowProc | WNDPROC | DefWindowProc | function that processes window messages | Win 32 | diff --git a/RenderSystems/GLSupport/CMakeLists.txt b/RenderSystems/GLSupport/CMakeLists.txt index c567c16bac0..80d18dd1e67 100644 --- a/RenderSystems/GLSupport/CMakeLists.txt +++ b/RenderSystems/GLSupport/CMakeLists.txt @@ -13,6 +13,7 @@ if(EGL_FOUND) cmake_dependent_option(OGRE_GLSUPPORT_USE_EGL "use EGL for GL Context Creation instead of GLX/ WGL" TRUE "NOT WIN32" FALSE) + cmake_dependent_option(OGRE_GLSUPPORT_USE_WAYLAND "use Wayland window manager" FALSE "UNIX;NOT APPLE;NOT EMSCRIPTEN;NOT ANDROID" FALSE) endif() if(ANDROID) @@ -64,13 +65,26 @@ elseif (APPLE) set(PLATFORM_LIBS "-framework AppKit" ${OPENGL_gl_LIBRARY}) elseif (UNIX) if(OGRE_GLSUPPORT_USE_EGL) - file(GLOB PLATFORM_HEADERS "include/EGL/X11/*.h" "include/EGL/*.h") - file(GLOB PLATFORM_SOURCES "src/EGL/X11/*.cpp" "src/EGL/*.cpp" "src/X11/*.cpp") - - set(NATIVE_INCLUDES - ${CMAKE_CURRENT_SOURCE_DIR}/include/EGL + list(APPEND _EGL_HEADERS "include/EGL/*.h") + list(APPEND _EGL_SOURCES "src/EGL/*.cpp") + list(APPEND NATIVE_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include/EGL) + if(OGRE_GLSUPPORT_USE_WAYLAND) + list(APPEND _EGL_HEADERS "include/EGL/Wayland/*.h") + list(APPEND _EGL_SOURCES "src/EGL/Wayland/*.cpp") + list(APPEND NATIVE_INCLUDES + ${CMAKE_CURRENT_SOURCE_DIR}/include/EGL/Wayland) + set(PLATFORM_LIBS ${EGL_LIBRARIES} PkgConfig::waylands) + else() + list(APPEND _EGL_HEADERS "include/EGL/X11/*.h") + list(APPEND _EGL_SOURCES "src/EGL/X11/*.cpp") + list(APPEND _EGL_SOURCES "src/X11/*.cpp") + list(APPEND NATIVE_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include/EGL/X11) - set(PLATFORM_LIBS ${X11_LIBRARIES} ${X11_Xrandr_LIB} ${EGL_LIBRARIES}) + set(PLATFORM_LIBS ${X11_LIBRARIES} ${X11_Xrandr_LIB} ${EGL_LIBRARIES}) + endif() + + file(GLOB PLATFORM_HEADERS ${_EGL_HEADERS}) + file(GLOB PLATFORM_SOURCES ${_EGL_SOURCES}) else() file(GLOB PLATFORM_HEADERS "include/GLX/*.h") file(GLOB PLATFORM_SOURCES "src/GLX/*.cpp" "src/X11/*.cpp") @@ -85,7 +99,9 @@ elseif (UNIX) set(PLATFORM_LIBS ${X11_LIBRARIES} ${X11_Xrandr_LIB} ${OPENGL_glx_LIBRARY}) endif() - list(APPEND NATIVE_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/src/X11/") + if(NOT OGRE_GLSUPPORT_USE_WAYLAND) + list(APPEND NATIVE_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/src/X11/") + endif() endif () file(GLOB GLSUPPORT_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") @@ -116,6 +132,10 @@ target_include_directories(OgreGLSupport PUBLIC "$" PRIVATE "$") + if(OGRE_GLSUPPORT_USE_WAYLAND) + target_compile_definitions(OgreGLSupport PRIVATE OGRE_WAYLAND) + endif() + set_property(TARGET OgreGLSupport PROPERTY POSITION_INDEPENDENT_CODE ON) generate_export_header(OgreGLSupport EXPORT_MACRO_NAME _OgreGLExport diff --git a/RenderSystems/GLSupport/include/EGL/OgreEGLSupport.h b/RenderSystems/GLSupport/include/EGL/OgreEGLSupport.h index e4c0c3ccbde..5919e5b4cdc 100644 --- a/RenderSystems/GLSupport/include/EGL/OgreEGLSupport.h +++ b/RenderSystems/GLSupport/include/EGL/OgreEGLSupport.h @@ -30,6 +30,17 @@ THE SOFTWARE. #ifndef __EGLSupport_H__ #define __EGLSupport_H__ +#ifndef OGRE_WAYLAND +// Tell EGL that we are using X11 (to select the appropriate definitions) +#define USE_X11 +#else +// Tell EGL to not include X11 headers +#define EGL_NO_X11 +// Tell EGL that we are using wayland +#ifndef WL_EGL_PLATFORM +#define WL_EGL_PLATFORM 1 +#endif +#endif #include "OgreGLNativeSupport.h" #include diff --git a/RenderSystems/GLSupport/include/EGL/Wayland/OgreWaylandEGLSupport.h b/RenderSystems/GLSupport/include/EGL/Wayland/OgreWaylandEGLSupport.h new file mode 100644 index 00000000000..f2dbcc71749 --- /dev/null +++ b/RenderSystems/GLSupport/include/EGL/Wayland/OgreWaylandEGLSupport.h @@ -0,0 +1,48 @@ +// This file is part of the OGRE project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at https://www.ogre3d.org/licensing. +// SPDX-License-Identifier: MIT + +#ifndef __WaylandEGLSupport_H__ +#define __WaylandEGLSupport_H__ + +#include +#include // include before egl + +#include "OgreEGLSupport.h" +#include + +namespace Ogre +{ +class _OgrePrivate WaylandEGLSupport : public EGLSupport +{ +public: + wl_surface* mWlSurface; + bool mIsExternalDisplay; + +protected: + VideoModes mCbVideoModes; + +public: + WaylandEGLSupport(int profile); + virtual ~WaylandEGLSupport(); + + inline void setNativeDisplay(NativeDisplayType t) + { + mIsExternalDisplay = true; + mNativeDisplay = t; + } + NativeDisplayType getNativeDisplay(void); + // This just sets the native variables needed by EGLSupport::getGLDisplay + // Then it calls EGLSupport::getGLDisplay to do the rest of the work. + EGLDisplay getGLDisplay(); + void doInit(); + + RenderWindow* newWindow(const String& name, unsigned int width, unsigned int height, bool fullScreen, + const NameValuePairList* miscParams = 0) override; + +}; + +} // namespace Ogre + +#endif diff --git a/RenderSystems/GLSupport/include/EGL/Wayland/OgreWaylandEGLWindow.h b/RenderSystems/GLSupport/include/EGL/Wayland/OgreWaylandEGLWindow.h new file mode 100644 index 00000000000..f5ab5aeb670 --- /dev/null +++ b/RenderSystems/GLSupport/include/EGL/Wayland/OgreWaylandEGLWindow.h @@ -0,0 +1,33 @@ +// This file is part of the OGRE project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at https://www.ogre3d.org/licensing. +// SPDX-License-Identifier: MIT + +#ifndef __WaylandEGLWindow_H__ +#define __WaylandEGLWindow_H__ + +#include "OgreEGLWindow.h" +#include "OgreWaylandEGLSupport.h" + +namespace Ogre +{ +class _OgrePrivate WaylandEGLWindow : public EGLWindow +{ +protected: + WaylandEGLSupport* mGLSupport; + + void initNativeCreatedWindow(const NameValuePairList* miscParams); + void createNativeWindow(uint& width, uint& height); + void resize(unsigned int width, unsigned int height) override; + void windowMovedOrResized() override; + +public: + WaylandEGLWindow(WaylandEGLSupport* glsupport); + virtual ~WaylandEGLWindow(); + + void create(const String& name, unsigned int width, unsigned int height, bool fullScreen, + const NameValuePairList* miscParams) override; +}; +} // namespace Ogre + +#endif diff --git a/RenderSystems/GLSupport/include/EGL/X11/OgreX11EGLSupport.h b/RenderSystems/GLSupport/include/EGL/X11/OgreX11EGLSupport.h index b6cc520827f..15c49b52680 100644 --- a/RenderSystems/GLSupport/include/EGL/X11/OgreX11EGLSupport.h +++ b/RenderSystems/GLSupport/include/EGL/X11/OgreX11EGLSupport.h @@ -30,9 +30,6 @@ THE SOFTWARE. #ifndef __X11EGLSupport_H__ #define __X11EGLSupport_H__ -// Tell EGL that we are using X11 (to select the appropriate definitions) -#define USE_X11 - #include "OgreEGLSupport.h" #ifndef Status diff --git a/RenderSystems/GLSupport/src/EGL/Wayland/OgreWaylandEGLSupport.cpp b/RenderSystems/GLSupport/src/EGL/Wayland/OgreWaylandEGLSupport.cpp new file mode 100644 index 00000000000..8317958029c --- /dev/null +++ b/RenderSystems/GLSupport/src/EGL/Wayland/OgreWaylandEGLSupport.cpp @@ -0,0 +1,129 @@ +// This file is part of the OGRE project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at https://www.ogre3d.org/licensing. +// SPDX-License-Identifier: MIT + +#include "OgreException.h" +#include "OgreLogManager.h" +#include "OgreRoot.h" +#include "OgreStringConverter.h" + +#include "OgreWaylandEGLSupport.h" +#include "OgreWaylandEGLWindow.h" + +#include "OgreGLUtil.h" + +namespace Ogre +{ + +GLNativeSupport* getGLSupport(int profile) { return new WaylandEGLSupport(profile); } + +WaylandEGLSupport::WaylandEGLSupport(int profile) : EGLSupport(profile) +{ + mWlSurface = nullptr; + mIsExternalDisplay = false; +} + +void WaylandEGLSupport::doInit() +{ + // A connection that is NOT shared to enable independent event processing: + mNativeDisplay = getNativeDisplay(); + + // A connection that might be shared with the application for GL rendering: + mGLDisplay = getGLDisplay(); + + if (mNativeDisplay == EGL_DEFAULT_DISPLAY) + { + // fake video mode + mCurrentMode.width = 0; + mCurrentMode.height = 0; + mCurrentMode.refreshRate = 0; + mVideoModes.push_back(mCurrentMode); + } + + mOriginalMode = mCurrentMode; + + EGLConfig* glConfigs; + int config, nConfigs = 0; + + glConfigs = chooseGLConfig(nullptr, &nConfigs); + + for (config = 0; config < nConfigs; config++) + { + int caveat, samples; + + getGLConfigAttrib(glConfigs[config], EGL_CONFIG_CAVEAT, &caveat); + + if (caveat != EGL_SLOW_CONFIG) + { + getGLConfigAttrib(glConfigs[config], EGL_SAMPLES, &samples); + mFSAALevels.push_back(samples); + } + } + + free(glConfigs); +} + +WaylandEGLSupport::~WaylandEGLSupport() +{ + if (mNativeDisplay) + { + if (!mIsExternalDisplay) + { + wl_display_disconnect(mNativeDisplay); + } + } + + if (mGLDisplay) + { + eglTerminate(mGLDisplay); + } +} + +NativeDisplayType WaylandEGLSupport::getNativeDisplay() +{ + if (!mNativeDisplay) + { + mNativeDisplay = wl_display_connect(nullptr); + if (mNativeDisplay == nullptr) + { + LogManager::getSingleton().logWarning("Couldn't connect to Wayland display"); + return mNativeDisplay; + } + + if (mNativeDisplay == EGL_DEFAULT_DISPLAY) + { + LogManager::getSingleton().logWarning("Couldn't open Wayland display"); + return mNativeDisplay; + } + } + + return mNativeDisplay; +} + +RenderWindow* WaylandEGLSupport::newWindow(const String& name, unsigned int width, unsigned int height, bool fullScreen, + const NameValuePairList* miscParams) +{ + EGLWindow* window = new WaylandEGLWindow(this); + + window->create(name, width, height, fullScreen, miscParams); + + return window; +} + +// WaylandEGLSupport::getGLDisplay sets up the native variable +// then calls EGLSupport::getGLDisplay +EGLDisplay WaylandEGLSupport::getGLDisplay() +{ + if (!mNativeDisplay) + { + mNativeDisplay = getNativeDisplay(); + } + if (!mGLDisplay) + { + return EGLSupport::getGLDisplay(); + } + return mGLDisplay; +} + +} // namespace Ogre diff --git a/RenderSystems/GLSupport/src/EGL/Wayland/OgreWaylandEGLWindow.cpp b/RenderSystems/GLSupport/src/EGL/Wayland/OgreWaylandEGLWindow.cpp new file mode 100644 index 00000000000..10cf45cb210 --- /dev/null +++ b/RenderSystems/GLSupport/src/EGL/Wayland/OgreWaylandEGLWindow.cpp @@ -0,0 +1,259 @@ +// This file is part of the OGRE project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at https://www.ogre3d.org/licensing. +// SPDX-License-Identifier: MIT + +#include "OgreException.h" +#include "OgreLogManager.h" +#include "OgreRoot.h" +#include "OgreStringConverter.h" +#include "OgreViewport.h" + +#include "OgreWaylandEGLSupport.h" +#include "OgreWaylandEGLWindow.h" + +#include +#include + +namespace Ogre +{ + +WaylandEGLWindow::WaylandEGLWindow(WaylandEGLSupport* glsupport) : EGLWindow(glsupport) +{ + mGLSupport = glsupport; + mNativeDisplay = nullptr; +} + +WaylandEGLWindow::~WaylandEGLWindow() +{ + if (mWindow && mIsTopLevel) + { + if (!mIsExternal) + wl_egl_window_destroy(mWindow); + } + mWindow = nullptr; +} + +void WaylandEGLWindow::initNativeCreatedWindow(const NameValuePairList* miscParams) +{ + if (miscParams) + { + NameValuePairList::const_iterator opt; + NameValuePairList::const_iterator end = miscParams->end(); + + if ((opt = miscParams->find("externalWlDisplay")) != end) + { + mNativeDisplay = (wl_display*)StringConverter::parseSizeT(opt->second); + mGLSupport->setNativeDisplay(mNativeDisplay); + } + if ((opt = miscParams->find("externalWlSurface")) != end) + { + mGLSupport->mWlSurface = (wl_surface*)StringConverter::parseSizeT(opt->second); + } + } + OgreAssert(mGLSupport->mWlSurface, "externalWlSurface required"); +} + +void WaylandEGLWindow::createNativeWindow(uint& width, uint& height) +{ + mEglDisplay = mGLSupport->getGLDisplay(); + + if (!mWindow) + { + mWindow = wl_egl_window_create(mGLSupport->mWlSurface, width, height); + } + + if (mWindow == EGL_NO_SURFACE) + { + OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Could not create EGL window"); + } + + if (mIsFullScreen) + { + switchFullScreen(true); + } + + wl_surface_commit(mGLSupport->mWlSurface); + wl_display_dispatch_pending(mNativeDisplay); + wl_display_flush(mNativeDisplay); +} + +void WaylandEGLWindow::resize(uint width, uint height) +{ + + if (mClosed) + { + return; + } + + if (mWidth == width && mHeight == height) + { + return; + } + + if (width != 0 && height != 0) + { + if (mWindow) + { + wl_egl_window_resize(mWindow, width, height, 0, 0); + mWidth = width; + mHeight = height; + + for (auto& it : mViewportList) + it.second->_updateDimensions(); + + wl_surface_damage(mGLSupport->mWlSurface, 0, 0, mWidth, mHeight); + wl_surface_commit(mGLSupport->mWlSurface); + wl_display_dispatch_pending(mNativeDisplay); + wl_display_flush(mNativeDisplay); + } + } +} + +void WaylandEGLWindow::windowMovedOrResized() +{ + if (mClosed || !mWindow) + return; + + int width, height; + wl_egl_window_get_attached_size(mWindow, &width, &height); + resize(width, height); +} + +void WaylandEGLWindow::create(const String& name, uint width, uint height, bool fullScreen, + const NameValuePairList* miscParams) +{ + int samples = 0; + short frequency = 0; + int maxBufferSize(32), minBufferSize(16), maxDepthSize(16), maxStencilSize(0); + bool vsync = false; + ::EGLContext eglContext = nullptr; + unsigned int vsyncInterval = 1; + + mIsFullScreen = fullScreen; + + if (miscParams) + { + NameValuePairList::const_iterator opt; + NameValuePairList::const_iterator end = miscParams->end(); + + if ((opt = miscParams->find("currentGLContext")) != end && StringConverter::parseBool(opt->second)) + { + eglContext = eglGetCurrentContext(); + EGL_CHECK_ERROR + if (!eglContext) + { + OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, + "currentGLContext was specified with no current GL context", "EGLWindow::create"); + } + + mEglDisplay = eglGetCurrentDisplay(); + EGL_CHECK_ERROR + } + + if ((opt = miscParams->find("maxColourBufferSize")) != end) + { + maxBufferSize = Ogre::StringConverter::parseInt(opt->second); + } + + if ((opt = miscParams->find("maxDepthBufferSize")) != end) + { + maxDepthSize = Ogre::StringConverter::parseInt(opt->second); + } + + if ((opt = miscParams->find("maxStencilBufferSize")) != end) + { + maxStencilSize = Ogre::StringConverter::parseInt(opt->second); + } + + if ((opt = miscParams->find("minColourBufferSize")) != end) + { + minBufferSize = Ogre::StringConverter::parseInt(opt->second); + if (minBufferSize > maxBufferSize) + minBufferSize = maxBufferSize; + } + + if ((opt = miscParams->find("FSAA")) != end) + { + samples = StringConverter::parseUnsignedInt(opt->second); + } + + if ((opt = miscParams->find("displayFrequency")) != end) + { + frequency = (short)StringConverter::parseInt(opt->second); + } + + if ((opt = miscParams->find("vsync")) != end) + { + vsync = StringConverter::parseBool(opt->second); + } + + if ((opt = miscParams->find("vsyncInterval")) != end) + vsyncInterval = StringConverter::parseUnsignedInt(opt->second); + + if ((opt = miscParams->find("gamma")) != end) + { + mHwGamma = StringConverter::parseBool(opt->second); + } + + if ((opt = miscParams->find("externalGLControl")) != end) + { + mIsExternalGLControl = StringConverter::parseBool(opt->second); + } + + OgreAssert(miscParams->find("parentWindowHandle") == end && miscParams->find("externalWindowHandle") == end, + "Recompile with OGRE_GLSUPPORT_USE_WAYLAND=OFF"); + } + + initNativeCreatedWindow(miscParams); + mGLSupport->doInit(); + + if (!mEglConfig) + { + int MSAAminAttribs[] = { + EGL_BUFFER_SIZE, minBufferSize, + EGL_DEPTH_SIZE, 16, + EGL_SAMPLE_BUFFERS, 1, + EGL_SAMPLES, samples, + EGL_NONE + }; + int MSAAmaxAttribs[] = { + EGL_BUFFER_SIZE, maxBufferSize, + EGL_DEPTH_SIZE, maxDepthSize, + EGL_STENCIL_SIZE, maxStencilSize, + EGL_SAMPLE_BUFFERS, 1, + EGL_SAMPLES, samples, + EGL_NONE + }; + + mEglConfig = mGLSupport->selectGLConfig(MSAAminAttribs, MSAAmaxAttribs); + } + + if (!mIsTopLevel) + { + mIsFullScreen = false; + } + + if (mIsFullScreen) + { + mGLSupport->switchMode(width, height, frequency); + } + + createNativeWindow(width, height); + mEglSurface = createSurfaceFromWindow(mGLSupport->getGLDisplay(), mWindow); + mContext = createEGLContext(eglContext); + + // apply vsync settings. call setVSyncInterval first to avoid + // setting vsync more than once. + setVSyncInterval(vsyncInterval); + setVSyncEnabled(vsync); + + mName = name; + mWidth = width; + mHeight = height; + + finaliseWindow(); + wl_surface_commit(mGLSupport->mWlSurface); +} + +} // namespace Ogre diff --git a/RenderSystems/GLSupport/src/EGL/X11/OgreX11EGLWindow.cpp b/RenderSystems/GLSupport/src/EGL/X11/OgreX11EGLWindow.cpp index 5238cab1e1e..a78d7b5156a 100644 --- a/RenderSystems/GLSupport/src/EGL/X11/OgreX11EGLWindow.cpp +++ b/RenderSystems/GLSupport/src/EGL/X11/OgreX11EGLWindow.cpp @@ -94,6 +94,8 @@ namespace Ogre { NameValuePairList::const_iterator opt; NameValuePairList::const_iterator end = miscParams->end(); + OgreAssert(miscParams->find("externalWlDisplay") == end, "Recompile with OGRE_GLSUPPORT_USE_WAYLAND=ON"); + if ((opt = miscParams->find("parentWindowHandle")) != end || (opt = miscParams->find("externalWindowHandle")) != end) {