From d9df7db130ac22a6691bc4eb73ad0f691e999d7b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 10 Dec 2025 03:20:54 +0100 Subject: [PATCH] Allow choosing between GLX and EGL during run-time The same library binary can now be used to use either GLX or EGL for wxGLCanvas implementation instead of the choice being done at build time (by either always using EGL if it is enabled or always using GLX otherwise). New wxGLCanvas::PreferGLX() function (available only if wxHAS_GLX is defined) can be used to request using GLX even if EGL is available, otherwise EGL is used by default, just as before. Additionally new "opengl.egl" system option can be used to the same effect, mostly to allow users to set "wx_opengl_egl" environment variable to 0 to use GLX if possible, i.e. with X11 and not Wayland. --- Makefile.in | 29 +- build/bakefiles/files.bkl | 7 +- build/cmake/files.cmake | 7 +- build/cmake/init.cmake | 1 + build/cmake/setup.h.in | 5 +- build/files | 7 +- configure | 53 +--- configure.ac | 2 +- docs/changes.txt | 4 + docs/doxygen/mainpages/const_cpp.h | 4 + include/wx/android/setup.h | 8 - include/wx/glcanvas.h | 36 +-- include/wx/gtk/glcanvas.h | 15 +- include/wx/gtk/setup.h | 8 - include/wx/msw/setup.h | 8 - include/wx/osx/setup.h | 8 - include/wx/setup_inc.h | 8 - include/wx/univ/setup.h | 8 - include/wx/unix/{glx11.h => glcanvas.h} | 88 +++--- include/wx/unix/glegl.h | 205 ------------ include/wx/unix/private/glcanvas.h | 162 ++++++++++ include/wx/unix/private/glegl.h | 188 +++++++++++ include/wx/unix/private/glx11.h | 131 ++++++++ include/wx/x11/glcanvas.h | 6 +- interface/wx/glcanvas.h | 34 +- samples/opengl/cube/cube.cpp | 36 +++ samples/opengl/cube/cube.h | 1 + setup.h.in | 5 +- setup.h_vms | 2 - src/gtk/glcanvas.cpp | 22 +- src/unix/glcanvas.cpp | 356 +++++++++++++++++++++ src/unix/glegl.cpp | 373 ++++++++++++---------- src/unix/glx11.cpp | 398 ++++++++++++------------ 33 files changed, 1428 insertions(+), 797 deletions(-) rename include/wx/unix/{glx11.h => glcanvas.h} (58%) delete mode 100644 include/wx/unix/glegl.h create mode 100644 include/wx/unix/private/glcanvas.h create mode 100644 include/wx/unix/private/glegl.h create mode 100644 include/wx/unix/private/glx11.h create mode 100644 src/unix/glcanvas.cpp diff --git a/Makefile.in b/Makefile.in index d228908e41..67aea962c8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2630,13 +2630,14 @@ COND_PLATFORM_WIN32_1_GTK_PLATFORM_HDR = \ @COND_TOOLKIT_MSW@WEBVIEW_PLATFORM_HDR = \ @COND_TOOLKIT_MSW@ wx/msw/webviewhistoryitem_ie.h wx/msw/webview_ie.h \ @COND_TOOLKIT_MSW@ wx/msw/webview_edge.h -@COND_TOOLKIT_GTK@OPENGL_PLATFORM_HDR = wx/unix/glx11.h \ -@COND_TOOLKIT_GTK@ wx/gtk/glcanvas.h wx/unix/glegl.h +@COND_TOOLKIT_GTK@OPENGL_PLATFORM_HDR = wx/gtk/glcanvas.h \ +@COND_TOOLKIT_GTK@ wx/unix/glcanvas.h @COND_TOOLKIT_MSW@OPENGL_PLATFORM_HDR = wx/msw/glcanvas.h @COND_TOOLKIT_OSX_COCOA@OPENGL_PLATFORM_HDR = wx/osx/glcanvas.h @COND_TOOLKIT_OSX_IPHONE@OPENGL_PLATFORM_HDR = wx/osx/glcanvas.h @COND_TOOLKIT_QT@OPENGL_PLATFORM_HDR = wx/qt/glcanvas.h -@COND_TOOLKIT_X11@OPENGL_PLATFORM_HDR = wx/unix/glx11.h wx/x11/glcanvas.h +@COND_TOOLKIT_X11@OPENGL_PLATFORM_HDR = wx/x11/glcanvas.h \ +@COND_TOOLKIT_X11@ wx/unix/glcanvas.h @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2@AUI_PLATFORM_HDR = wx/aui/tabartgtk.h @COND_TOOLKIT_MSW@AUI_PLATFORM_HDR = wx/aui/tabartmsw.h wx/aui/barartmsw.h COND_PLATFORM_MACOSX_1_BASE_PLATFORM_HDR = \ @@ -12155,7 +12156,8 @@ COND_USE_SOVERSOLARIS_1___gldll___so_symlinks_uninst_cmd = rm -f \ @COND_USE_SOVERSOLARIS_1@__gldll___so_symlinks_uninst_cmd = $(COND_USE_SOVERSOLARIS_1___gldll___so_symlinks_uninst_cmd) @COND_PLATFORM_WIN32_1@__gldll___win32rc = gldll_version_rc.o @COND_TOOLKIT_GTK@__OPENGL_PLATFORM_SRC_OBJECTS = \ -@COND_TOOLKIT_GTK@ gldll_glx11.o gldll_gtk_glcanvas.o gldll_glegl.o +@COND_TOOLKIT_GTK@ gldll_glx11.o gldll_gtk_glcanvas.o gldll_glegl.o \ +@COND_TOOLKIT_GTK@ gldll_unix_glcanvas.o @COND_TOOLKIT_MSW@__OPENGL_PLATFORM_SRC_OBJECTS = gldll_msw_glcanvas.o @COND_TOOLKIT_OSX_COCOA@__OPENGL_PLATFORM_SRC_OBJECTS \ @COND_TOOLKIT_OSX_COCOA@ = gldll_glcanvas_osx.o gldll_cocoa_glcanvas.o @@ -12163,7 +12165,7 @@ COND_USE_SOVERSOLARIS_1___gldll___so_symlinks_uninst_cmd = rm -f \ @COND_TOOLKIT_OSX_IPHONE@ = gldll_glcanvas_osx.o gldll_iphone_glcanvas.o @COND_TOOLKIT_QT@__OPENGL_PLATFORM_SRC_OBJECTS = gldll_qt_glcanvas.o @COND_TOOLKIT_X11@__OPENGL_PLATFORM_SRC_OBJECTS = \ -@COND_TOOLKIT_X11@ gldll_x11_glcanvas.o gldll_glx11.o +@COND_TOOLKIT_X11@ gldll_x11_glcanvas.o gldll_glx11.o gldll_unix_glcanvas.o COND_MONOLITHIC_0___WXLIBGLDEP_CORE_p = \ -lwx_$(PORTNAME)$(WXUNIVNAME)u$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_core-$(WX_RELEASE)$(HOST_SUFFIX) @COND_MONOLITHIC_0@__WXLIBGLDEP_CORE_p = $(COND_MONOLITHIC_0___WXLIBGLDEP_CORE_p) @@ -12186,7 +12188,8 @@ COND_SHARED_0_USE_GUI_1_USE_OPENGL_1___gllib___depname = \ @COND_USE_PCH_1@_____pch_wxprec_gllib_wx_wxprec_h_gch___depname \ @COND_USE_PCH_1@ = ./.pch/wxprec_gllib/wx/wxprec.h.gch @COND_TOOLKIT_GTK@__OPENGL_PLATFORM_SRC_OBJECTS_1 = \ -@COND_TOOLKIT_GTK@ gllib_glx11.o gllib_gtk_glcanvas.o gllib_glegl.o +@COND_TOOLKIT_GTK@ gllib_glx11.o gllib_gtk_glcanvas.o gllib_glegl.o \ +@COND_TOOLKIT_GTK@ gllib_unix_glcanvas.o @COND_TOOLKIT_MSW@__OPENGL_PLATFORM_SRC_OBJECTS_1 = gllib_msw_glcanvas.o @COND_TOOLKIT_OSX_COCOA@__OPENGL_PLATFORM_SRC_OBJECTS_1 \ @COND_TOOLKIT_OSX_COCOA@ = gllib_glcanvas_osx.o gllib_cocoa_glcanvas.o @@ -12194,7 +12197,7 @@ COND_SHARED_0_USE_GUI_1_USE_OPENGL_1___gllib___depname = \ @COND_TOOLKIT_OSX_IPHONE@ = gllib_glcanvas_osx.o gllib_iphone_glcanvas.o @COND_TOOLKIT_QT@__OPENGL_PLATFORM_SRC_OBJECTS_1 = gllib_qt_glcanvas.o @COND_TOOLKIT_X11@__OPENGL_PLATFORM_SRC_OBJECTS_1 = \ -@COND_TOOLKIT_X11@ gllib_x11_glcanvas.o gllib_glx11.o +@COND_TOOLKIT_X11@ gllib_x11_glcanvas.o gllib_glx11.o gllib_unix_glcanvas.o @COND_SHARED_1@____wxgl_namedll_DEP = $(__gldll___depname) @COND_SHARED_0@____wxgl_namelib_DEP = $(__gllib___depname) COND_WITH_PLUGIN_SDL_1___sound_sdl___depname = \ @@ -34418,6 +34421,12 @@ gldll_x11_glcanvas.o: $(srcdir)/src/x11/glcanvas.cpp $(GLDLL_ODEP) @COND_TOOLKIT_X11@gldll_glx11.o: $(srcdir)/src/unix/glx11.cpp $(GLDLL_ODEP) @COND_TOOLKIT_X11@ $(CXXC) -c -o $@ $(GLDLL_CXXFLAGS) $(srcdir)/src/unix/glx11.cpp +@COND_TOOLKIT_GTK@gldll_unix_glcanvas.o: $(srcdir)/src/unix/glcanvas.cpp $(GLDLL_ODEP) +@COND_TOOLKIT_GTK@ $(CXXC) -c -o $@ $(GLDLL_CXXFLAGS) $(srcdir)/src/unix/glcanvas.cpp + +@COND_TOOLKIT_X11@gldll_unix_glcanvas.o: $(srcdir)/src/unix/glcanvas.cpp $(GLDLL_ODEP) +@COND_TOOLKIT_X11@ $(CXXC) -c -o $@ $(GLDLL_CXXFLAGS) $(srcdir)/src/unix/glcanvas.cpp + gllib_glcmn.o: $(srcdir)/src/common/glcmn.cpp $(GLLIB_ODEP) $(CXXC) -c -o $@ $(GLLIB_CXXFLAGS) $(srcdir)/src/common/glcmn.cpp @@ -34454,6 +34463,12 @@ gllib_x11_glcanvas.o: $(srcdir)/src/x11/glcanvas.cpp $(GLLIB_ODEP) @COND_TOOLKIT_X11@gllib_glx11.o: $(srcdir)/src/unix/glx11.cpp $(GLLIB_ODEP) @COND_TOOLKIT_X11@ $(CXXC) -c -o $@ $(GLLIB_CXXFLAGS) $(srcdir)/src/unix/glx11.cpp +@COND_TOOLKIT_GTK@gllib_unix_glcanvas.o: $(srcdir)/src/unix/glcanvas.cpp $(GLLIB_ODEP) +@COND_TOOLKIT_GTK@ $(CXXC) -c -o $@ $(GLLIB_CXXFLAGS) $(srcdir)/src/unix/glcanvas.cpp + +@COND_TOOLKIT_X11@gllib_unix_glcanvas.o: $(srcdir)/src/unix/glcanvas.cpp $(GLLIB_ODEP) +@COND_TOOLKIT_X11@ $(CXXC) -c -o $@ $(GLLIB_CXXFLAGS) $(srcdir)/src/unix/glcanvas.cpp + sound_sdl_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(CXXC) -c -o $@ $(SOUND_SDL_CXXFLAGS) $(srcdir)/src/unix/sound_sdl.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 3eea13d4a6..92e811a93c 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -2908,12 +2908,12 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/unix/glx11.cpp src/gtk/glcanvas.cpp src/unix/glegl.cpp + src/unix/glcanvas.cpp - wx/unix/glx11.h wx/gtk/glcanvas.h - wx/unix/glegl.h + wx/unix/glcanvas.h @@ -2937,11 +2937,12 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/x11/glcanvas.cpp src/unix/glx11.cpp + src/unix/glcanvas.cpp - wx/unix/glx11.h wx/x11/glcanvas.h + wx/unix/glcanvas.h diff --git a/build/cmake/files.cmake b/build/cmake/files.cmake index 2a17698af5..b9584e6da8 100644 --- a/build/cmake/files.cmake +++ b/build/cmake/files.cmake @@ -2700,12 +2700,12 @@ set(OPENGL_GTK_SRC src/gtk/glcanvas.cpp src/unix/glx11.cpp src/unix/glegl.cpp + src/unix/glcanvas.cpp ) set(OPENGL_GTK_HDR wx/gtk/glcanvas.h - wx/unix/glx11.h - wx/unix/glegl.h + wx/unix/glcanvas.h ) set(OPENGL_OSX_COCOA_SRC @@ -2729,11 +2729,12 @@ set(OPENGL_OSX_IPHONE_HDR set(OPENGL_X11_SRC src/x11/glcanvas.cpp src/unix/glx11.cpp + src/unix/glcanvas.cpp ) set(OPENGL_X11_HDR wx/x11/glcanvas.h - wx/unix/glx11.h + wx/unix/glcanvas.h ) set(OPENGL_QT_SRC diff --git a/build/cmake/init.cmake b/build/cmake/init.cmake index ad2e6fa8ae..45a12ede07 100644 --- a/build/cmake/init.cmake +++ b/build/cmake/init.cmake @@ -537,6 +537,7 @@ if(wxUSE_GUI) # library directly like this to avoid link problems. set(OPENGL_LIBRARIES ${OPENGL_egl_LIBRARY} ${OPENGL_LIBRARIES}) endif() + set(wxHAS_EGL 1) set(OPENGL_INCLUDE_DIR ${OPENGL_INCLUDE_DIR} ${OPENGL_EGL_INCLUDE_DIRS}) find_package(WAYLANDEGL) if(WAYLANDEGL_FOUND AND wxHAVE_GDK_WAYLAND) diff --git a/build/cmake/setup.h.in b/build/cmake/setup.h.in index 1c09d7d0ca..4984e38aa3 100644 --- a/build/cmake/setup.h.in +++ b/build/cmake/setup.h.in @@ -497,8 +497,6 @@ #cmakedefine01 wxUSE_GLCANVAS -#cmakedefine01 wxUSE_GLCANVAS_EGL - #cmakedefine01 wxUSE_RICHTEXT @@ -1130,6 +1128,9 @@ /* Define if locale_t is available */ #cmakedefine HAVE_LOCALE_T 1 +/* Define if you have EGL support */ +#cmakedefine wxHAS_EGL 1 + /* Define if you have inotify_xxx() functions. */ #cmakedefine wxHAS_INOTIFY 1 diff --git a/build/files b/build/files index 52c7fc668f..55581da8e2 100644 --- a/build/files +++ b/build/files @@ -2668,13 +2668,13 @@ OPENGL_MSW_HDR = OPENGL_GTK_SRC = src/gtk/glcanvas.cpp + src/unix/glcanvas.cpp src/unix/glegl.cpp src/unix/glx11.cpp OPENGL_GTK_HDR = wx/gtk/glcanvas.h - wx/unix/glegl.h - wx/unix/glx11.h + wx/unix/glcanvas.h OPENGL_OSX_COCOA_SRC = src/osx/cocoa/glcanvas.mm @@ -2691,11 +2691,12 @@ OPENGL_OSX_IPHONE_HDR = wx/osx/glcanvas.h OPENGL_X11_SRC = + src/unix/glcanvas.cpp src/unix/glx11.cpp src/x11/glcanvas.cpp OPENGL_X11_HDR = - wx/unix/glx11.h + wx/unix/glcanvas.h wx/x11/glcanvas.h OPENGL_QT_SRC = diff --git a/configure b/configure index 4f4659542f..683aab187a 100755 --- a/configure +++ b/configure @@ -1362,7 +1362,6 @@ enable_accessibility enable_uiactionsim enable_dctransform enable_webviewwebkit -enable_glcanvasegl enable_palette enable_image enable_gif @@ -2339,7 +2338,6 @@ Optional Features: --enable-uiactionsim use wxUIActionSimulator --enable-dctransform use wxDC::SetTransformMatrix and related --enable-webviewwebkit use wxWebView WebKit backend - --disable-glcanvasegl disable wxGLCanvas EGL backend --enable-palette use wxPalette class --enable-image use wxImage class --enable-gif use gif images (GIF file format) @@ -12374,35 +12372,6 @@ fi eval "$wx_cv_use_webviewwebkit" - enablestring= - defaultval=$wxUSE_ALL_FEATURES - if test -z "$defaultval"; then - if test x"$enablestring" = xdisable; then - defaultval=yes - else - defaultval=no - fi - fi - - # Check whether --enable-glcanvasegl was given. -if test "${enable_glcanvasegl+set}" = set; then : - enableval=$enable_glcanvasegl; - if test "$enableval" = yes; then - wx_cv_use_glcanvasegl='wxUSE_GLCANVAS_EGL=yes' - else - wx_cv_use_glcanvasegl='wxUSE_GLCANVAS_EGL=no' - fi - -else - - wx_cv_use_glcanvasegl='wxUSE_GLCANVAS_EGL=${'DEFAULT_wxUSE_GLCANVAS_EGL":-$defaultval}" - -fi - - - eval "$wx_cv_use_glcanvasegl" - - enablestring= @@ -31298,7 +31267,6 @@ fi OPENGL_LIBS="-lGL" if test "$WXGTK3" = 1; then - if test "$wxUSE_GLCANVAS_EGL" != "no"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egl >= 1.4" >&5 @@ -31359,7 +31327,7 @@ fi echo "$EGL_PKG_ERRORS" >&5 - { $as_echo "$as_me:${as_lineno-$LINENO}: EGL 1.4+ not available. Will use GLX." >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: EGL 1.4+ not available. Will use GLX." >&5 $as_echo "$as_me: EGL 1.4+ not available. Will use GLX." >&6;} @@ -31367,7 +31335,7 @@ elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: EGL 1.4+ not available. Will use GLX." >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: EGL 1.4+ not available. Will use GLX." >&5 $as_echo "$as_me: EGL 1.4+ not available. Will use GLX." >&6;} @@ -31377,8 +31345,8 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - OPENGL_LIBS="$OPENGL_LIBS $EGL_LIBS" - $as_echo "#define wxUSE_GLCANVAS_EGL 1" >>confdefs.h + OPENGL_LIBS="$OPENGL_LIBS $EGL_LIBS" + $as_echo "#define wxHAS_EGL 1" >>confdefs.h pkg_failed=no @@ -31452,18 +31420,17 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - if test $wx_cv_gdk_wayland = "yes"; then - OPENGL_LIBS="$OPENGL_LIBS $WAYLAND_EGL_LIBS" - have_wayland=1 - fi + if test $wx_cv_gdk_wayland = "yes"; then + OPENGL_LIBS="$OPENGL_LIBS $WAYLAND_EGL_LIBS" + have_wayland=1 + fi fi fi - if test "$have_wayland" != 1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: wxGLCanvas will not have Wayland support" >&5 + if test "$have_wayland" != 1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: wxGLCanvas will not have Wayland support" >&5 $as_echo "$as_me: wxGLCanvas will not have Wayland support" >&6;} - fi fi fi fi diff --git a/configure.ac b/configure.ac index b0d83d7e11..f92963e36d 100644 --- a/configure.ac +++ b/configure.ac @@ -3461,7 +3461,7 @@ if test "$wxUSE_OPENGL" = "yes" -o "$wxUSE_OPENGL" = "auto"; then PKG_CHECK_MODULES(EGL, [egl >= 1.4], [ OPENGL_LIBS="$OPENGL_LIBS $EGL_LIBS" - AC_DEFINE(wxUSE_GLCANVAS_EGL) + AC_DEFINE(wxHAS_EGL) PKG_CHECK_MODULES(WAYLAND_EGL, [wayland-egl], [ if test $wx_cv_gdk_wayland = "yes"; then diff --git a/docs/changes.txt b/docs/changes.txt index d37c3d1538..a50bc6141a 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -237,6 +237,10 @@ Changes in behaviour which may result in build errors previously compiled doesn't compile any longer, please fix it to use either the ctor from RGB value or from string explicitly. +- wxGLCanvas::CreateSurface() which was previously enabled in build + configurations using EGL is not available any longer as exposing it doesn't + make sense when wxGLCanvas may use either EGL or GLX. + 3.3.2: (released 2025-??-??) ---------------------------- diff --git a/docs/doxygen/mainpages/const_cpp.h b/docs/doxygen/mainpages/const_cpp.h index 849cdded8d..bcdc5b9b3f 100644 --- a/docs/doxygen/mainpages/const_cpp.h +++ b/docs/doxygen/mainpages/const_cpp.h @@ -187,6 +187,10 @@ Currently the following symbols exist: ever, be necessary to use this symbol directly, functions such as wxWindow::FromDIP() and wxBitmap::GetLogicalSize() exist to hide the differences between the platforms with and without DPI-independent pixels.} +@itemdef{wxHAS_EGL, Defined if wxGLCanvas may use EGL for OpenGL context + creation (this symbol only exists in wxWidgets 3.3.2 and later).} +@itemdef{wxHAS_GLX, Defined if wxGLCanvas may use GLX for OpenGL context + creation (this symbol only exists in wxWidgets 3.3.2 and later).} @itemdef{wxHAS_IMAGE_RESOURCES, Defined if wxICON() and wxBITMAP() macros use images from (Windows) resources. Otherwise, these macros use XPMs.} @itemdef{wxHAS_MEMBER_DEFAULT, Defined if the currently used compiler supports diff --git a/include/wx/android/setup.h b/include/wx/android/setup.h index 0e07c4343c..f683b11042 100644 --- a/include/wx/android/setup.h +++ b/include/wx/android/setup.h @@ -1321,14 +1321,6 @@ // otherwise. #define wxUSE_GLCANVAS 1 -// Setting wxUSE_GLCANVAS_EGL to 1 enables OpenGL EGL backend. This will be -// automatically enabled if EGL support is detected. EGL support is only -// available under Unix platforms. -// -// Default is 0. -// -#define wxUSE_GLCANVAS_EGL 0 - // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/glcanvas.h b/include/wx/glcanvas.h index 918dd20fe2..cdc4242470 100644 --- a/include/wx/glcanvas.h +++ b/include/wx/glcanvas.h @@ -20,14 +20,10 @@ // Most ports have a single implementation of wxGLCanvas, but wxGTK has two: // legacy GLX-based one (also used by wxX11) and EGL-based one which is used -// when enabled by wxUSE_GLCANVAS_EGL. Although it is not user-settable, define -// wxUSE_GLCANVAS_GLX for consistency. -#if defined(__WXX11__) - #define wxUSE_GLCANVAS_GLX 1 -#elif defined(__WXGTK__) - #define wxUSE_GLCANVAS_GLX (!wxUSE_GLCANVAS_EGL) -#else - #define wxUSE_GLCANVAS_GLX 0 +// if support for EGL is available. wxHAS_EGL is defined by the build system +// but define wxHAS_GLX too for consistency, even if it's always available. +#if defined(__WXX11__) || defined(__WXGTK__) + #define wxHAS_GLX 1 #endif class WXDLLIMPEXP_FWD_GL wxGLCanvas; @@ -146,16 +142,16 @@ public: wxGLContextAttrs& PlatformDefaults(); void EndList(); // No more values can be chained -#if wxUSE_GLCANVAS_GLX +#ifdef wxHAS_GLX // Currently only used for X11 context creation bool x11Direct = false; // X11 direct render bool renderTypeRGBA = false; -#endif // wxUSE_GLCANVAS_GLX +#endif // wxHAS_GLX -#if wxUSE_GLCANVAS_EGL +#ifdef wxHAS_EGL // Used to select the kind of API used with EGL (OpenGL or OpenGL ES). bool useES = false; -#endif // wxUSE_GLCANVAS_EGL +#endif // wxHAS_EGL }; // ---------------------------------------------------------------------------- @@ -283,25 +279,27 @@ public: // as a parameter wxGLContextAttrs& GetGLCTXAttrs() { return m_GLCTXAttrs; } -protected: - // override this to implement SetColour() in GL_INDEX_MODE - // (currently only implemented in wxX11) - virtual int GetColourIndex(const wxColour& WXUNUSED(col)) { return -1; } + // Implementation only from now on. // check if the given extension name is present in the space-separated list // of extensions supported by the current implementation such as returned // by glXQueryExtensionsString() or glGetString(GL_EXTENSIONS) static bool IsExtensionInList(const char *list, const char *extension); - // For the case of "int* attribList" at ctor is != 0 - wxGLContextAttrs m_GLCTXAttrs; - // Extract pixel format and context attributes. // Return false if an unknown attribute is found. static bool ParseAttribList(const int* attribList, wxGLAttributes& dispAttrs, wxGLContextAttrs* ctxAttrs = nullptr); +protected: + // override this to implement SetColour() in GL_INDEX_MODE + // (currently only implemented in wxX11) + virtual int GetColourIndex(const wxColour& WXUNUSED(col)) { return -1; } + + // For the case of "int* attribList" at ctor is != 0 + wxGLContextAttrs m_GLCTXAttrs; + #if wxUSE_PALETTE // create default palette if we're not using RGBA mode // (not supported in most ports) diff --git a/include/wx/gtk/glcanvas.h b/include/wx/gtk/glcanvas.h index 32dde022cf..977b719859 100644 --- a/include/wx/gtk/glcanvas.h +++ b/include/wx/gtk/glcanvas.h @@ -10,23 +10,14 @@ #ifndef _WX_GLCANVAS_H_ #define _WX_GLCANVAS_H_ -#include "wx/setup.h" - -#if wxUSE_GLCANVAS_EGL - #include "wx/unix/glegl.h" - typedef wxGLCanvasEGL wxGLCanvasImpl; -#else - #include "wx/unix/glx11.h" - typedef wxGLCanvasX11 wxGLCanvasImpl; -#endif +#include "wx/unix/glcanvas.h" //--------------------------------------------------------------------------- // wxGLCanvas //--------------------------------------------------------------------------- -class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasImpl +class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasUnix { - typedef wxGLCanvasImpl BaseType; public: wxGLCanvas() = default; @@ -69,7 +60,7 @@ public: virtual bool SetBackgroundStyle(wxBackgroundStyle style) override; - // implement wxGLCanvasX11 methods + // implement wxGLCanvasUnix methods // -------------------------------- virtual unsigned long GetXWindow() const override; diff --git a/include/wx/gtk/setup.h b/include/wx/gtk/setup.h index a0a7d77c17..680e008815 100644 --- a/include/wx/gtk/setup.h +++ b/include/wx/gtk/setup.h @@ -1321,14 +1321,6 @@ // otherwise. #define wxUSE_GLCANVAS 1 -// Setting wxUSE_GLCANVAS_EGL to 1 enables OpenGL EGL backend. This will be -// automatically enabled if EGL support is detected. EGL support is only -// available under Unix platforms. -// -// Default is 0. -// -#define wxUSE_GLCANVAS_EGL 0 - // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/msw/setup.h b/include/wx/msw/setup.h index a1c003d000..1486b959f1 100644 --- a/include/wx/msw/setup.h +++ b/include/wx/msw/setup.h @@ -1321,14 +1321,6 @@ // otherwise. #define wxUSE_GLCANVAS 1 -// Setting wxUSE_GLCANVAS_EGL to 1 enables OpenGL EGL backend. This will be -// automatically enabled if EGL support is detected. EGL support is only -// available under Unix platforms. -// -// Default is 0. -// -#define wxUSE_GLCANVAS_EGL 0 - // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/osx/setup.h b/include/wx/osx/setup.h index aaee52b256..5bf95a043b 100644 --- a/include/wx/osx/setup.h +++ b/include/wx/osx/setup.h @@ -1328,14 +1328,6 @@ // otherwise. #define wxUSE_GLCANVAS 1 -// Setting wxUSE_GLCANVAS_EGL to 1 enables OpenGL EGL backend. This will be -// automatically enabled if EGL support is detected. EGL support is only -// available under Unix platforms. -// -// Default is 0. -// -#define wxUSE_GLCANVAS_EGL 0 - // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/setup_inc.h b/include/wx/setup_inc.h index cb4350ecfc..86499e826c 100644 --- a/include/wx/setup_inc.h +++ b/include/wx/setup_inc.h @@ -1317,14 +1317,6 @@ // otherwise. #define wxUSE_GLCANVAS 1 -// Setting wxUSE_GLCANVAS_EGL to 1 enables OpenGL EGL backend. This will be -// automatically enabled if EGL support is detected. EGL support is only -// available under Unix platforms. -// -// Default is 0. -// -#define wxUSE_GLCANVAS_EGL 0 - // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/univ/setup.h b/include/wx/univ/setup.h index 998b4b0c70..e2a0d6e557 100644 --- a/include/wx/univ/setup.h +++ b/include/wx/univ/setup.h @@ -1321,14 +1321,6 @@ // otherwise. #define wxUSE_GLCANVAS 1 -// Setting wxUSE_GLCANVAS_EGL to 1 enables OpenGL EGL backend. This will be -// automatically enabled if EGL support is detected. EGL support is only -// available under Unix platforms. -// -// Default is 0. -// -#define wxUSE_GLCANVAS_EGL 0 - // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/unix/glx11.h b/include/wx/unix/glcanvas.h similarity index 58% rename from include/wx/unix/glx11.h rename to include/wx/unix/glcanvas.h index 61db250e43..4f30324a03 100644 --- a/include/wx/unix/glx11.h +++ b/include/wx/unix/glcanvas.h @@ -1,22 +1,27 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: wx/unix/glx11.h -// Purpose: class common for all X11-based wxGLCanvas implementations +// Name: wx/unix/glcanvas.h +// Purpose: class common for wxGLCanvas implementations in wxGTK and wxX11 // Author: Vadim Zeitlin // Created: 2007-04-15 // Copyright: (c) 2007 Vadim Zeitlin // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// -#ifndef _WX_UNIX_GLX11_H_ -#define _WX_UNIX_GLX11_H_ +#ifndef _WX_UNIX_GLCANVAS_H_ +#define _WX_UNIX_GLCANVAS_H_ + +#include #include -typedef struct __GLXcontextRec* GLXContext; +// Forward declare struct from GL/glx.h typedef struct __GLXFBConfigRec* GLXFBConfig; +class wxGLContextImpl; +class wxGLCanvasUnixImpl; + // ---------------------------------------------------------------------------- -// wxGLContext +// wxGLContext: used as is in all ports // ---------------------------------------------------------------------------- class WXDLLIMPEXP_GL wxGLContext : public wxGLContextBase @@ -29,41 +34,35 @@ public: virtual bool SetCurrent(const wxGLCanvas& win) const override; + // Implementation only. + wxGLContextImpl* GetImpl() const { return m_impl.get(); } + private: - GLXContext m_glContext; + std::unique_ptr m_impl; wxDECLARE_CLASS(wxGLContext); }; // ---------------------------------------------------------------------------- -// wxGLCanvasX11 +// wxGLCanvasUnix: base class for port-specific wxGLCanvas // ---------------------------------------------------------------------------- -class WXDLLIMPEXP_GL wxGLCanvasX11 : public wxGLCanvasBase +class WXDLLIMPEXP_GL wxGLCanvasUnix : public wxGLCanvasBase { public: - // initialization and dtor - // ----------------------- - - // default ctor doesn't do anything, InitVisual() must be called - wxGLCanvasX11(); - - // initializes GLXFBConfig and XVisualInfo corresponding to the given attributes - bool InitVisual(const wxGLAttributes& dispAttrs); - - // frees XVisualInfo info - virtual ~wxGLCanvasX11(); - - - // implement wxGLCanvasBase methods - // -------------------------------- + virtual ~wxGLCanvasUnix(); virtual bool SwapBuffers() override; + virtual bool IsShownOnScreen() const override; - // X11-specific methods + // GLX-specific methods // -------------------- + // if both GLX and EGL are available, prefer using GLX instead of EGL used + // by default + static void PreferGLX(); + // return GLX version: 13 means 1.3 &c static int GetGLXVersion(); @@ -74,33 +73,21 @@ public: virtual unsigned long GetXWindow() const = 0; - // GLX-specific methods - // -------------------- + // Implementation only. + wxGLCanvasUnixImpl* GetImpl() const { return m_impl.get(); } - // override some wxWindow methods - // ------------------------------ + void* GetXVisualInfo() const; - // return true only if the window is realized: OpenGL context can't be - // created until we are - virtual bool IsShownOnScreen() const override; +protected: + wxGLCanvasUnix(); + bool InitVisual(const wxGLAttributes& dispAttrs); - // implementation only from now on - // ------------------------------- - - // get the GLXFBConfig/XVisualInfo we use - GLXFBConfig *GetGLXFBConfig() const { return m_fbc; } - void* GetXVisualInfo() const { return m_vi; } - - // initialize the global default GL visual, return false if matching visual - // not found - static bool InitDefaultVisualInfo(const int *attribList); + // This is only called by wxGTK but defined in any case. + void CallOnRealized(); private: - GLXFBConfig *m_fbc; - void* m_vi; - - bool m_swapIntervalSet = false; + std::unique_ptr m_impl; }; // ---------------------------------------------------------------------------- @@ -113,11 +100,11 @@ private: class WXDLLIMPEXP_GL wxGLApp : public wxGLAppBase { public: + wxGLApp() = default; + virtual bool InitGLVisual(const int *attribList) override; -#ifndef __WXGTK3__ - virtual void* GetXVisualInfo() override; -#endif // GTK < 3 + virtual void* GetXVisualInfo(); // and override this wxApp method to clean up virtual int OnExit() override; @@ -126,5 +113,4 @@ private: wxDECLARE_DYNAMIC_CLASS(wxGLApp); }; -#endif // _WX_UNIX_GLX11_H_ - +#endif // _WX_UNIX_GLCANVAS_H_ diff --git a/include/wx/unix/glegl.h b/include/wx/unix/glegl.h deleted file mode 100644 index 10d2f392be..0000000000 --- a/include/wx/unix/glegl.h +++ /dev/null @@ -1,205 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: wx/unix/glegl.h -// Purpose: class common for all EGL-based wxGLCanvas implementations -// Author: Scott Talbert -// Created: 2017-12-26 -// Copyright: (c) 2017 Scott Talbert -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _WX_UNIX_GLEGL_H_ -#define _WX_UNIX_GLEGL_H_ - -#include - -// This is to avoid including Wayland & EGL headers here to pollute namespace -struct wl_compositor; -struct wl_subcompositor; -struct wl_callback; -struct wl_egl_window; -struct wl_surface; -struct wl_region; -struct wl_subsurface; -typedef void *EGLDisplay; -typedef void *EGLConfig; -typedef void *EGLSurface; -typedef void *EGLContext; - -class wxGLContextAttrs; -class wxGLAttributes; - -// ---------------------------------------------------------------------------- -// wxGLContext -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_GL wxGLContext : public wxGLContextBase -{ -public: - wxGLContext(wxGLCanvas *win, - const wxGLContext *other = nullptr, - const wxGLContextAttrs *ctxAttrs = nullptr); - virtual ~wxGLContext(); - - virtual bool SetCurrent(const wxGLCanvas& win) const override; - -private: - EGLContext m_glContext; - - wxDECLARE_CLASS(wxGLContext); -}; - -// ---------------------------------------------------------------------------- -// wxGLCanvasEGL -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_GL wxGLCanvasEGL : public wxGLCanvasBase -{ -public: - // initialization and dtor - // ----------------------- - - // default ctor doesn't do anything, InitConfig() must be called - wxGLCanvasEGL() = default; - - // initializes EGLConfig corresponding to the given attributes - bool InitVisual(const wxGLAttributes& dispAttrs); - - // creates EGLSurface - bool CreateSurface(); - - virtual ~wxGLCanvasEGL(); - - // Wayland-specific callbacks - // -------------------------- - - void CreateWaylandSubsurface(); - void DestroyWaylandSubsurface(); - - // implement wxGLCanvasBase methods - // -------------------------------- - - virtual bool SwapBuffers() override; - - - // X11-specific methods - // -------------------- - - // get the X11 handle of this window - virtual unsigned long GetXWindow() const = 0; - - - // override some wxWindow methods - // ------------------------------ - - // return true only if the window is realized: OpenGL context can't be - // created until we are - virtual bool IsShownOnScreen() const override; - - - // implementation only from now on - // ------------------------------- - - // get the EGLConfig we use - EGLConfig GetEGLConfig() const { return m_config; } - EGLDisplay GetEGLDisplay() const { return m_display; } - EGLSurface GetEGLSurface() const { return m_surface; } - - static EGLDisplay GetDisplay(); - - // initialize the global default GL config, return false if matching config - // not found - static bool InitDefaultConfig(const int *attribList); - - // get the default EGL Config (may be null, shouldn't be freed by caller) - static EGLConfig GetDefaultConfig() { return ms_glEGLConfig; } - - // free the global GL visual, called by wxGLApp - static void FreeDefaultConfig(); - - // initializes EGLConfig - // - // returns nullptr if EGLConfig couldn't be initialized, otherwise caller - // is responsible for freeing the pointer - static EGLConfig InitConfig(const wxGLAttributes& dispAttrs); - - // Only called when using Wayland to indicate that we should be redrawn. - void OnWLFrameCallback(); - - wl_compositor *m_wlCompositor = nullptr; - wl_subcompositor *m_wlSubcompositor = nullptr; - wl_callback *m_wlFrameCallbackHandler = nullptr; - wl_egl_window *m_wlEGLWindow = nullptr; - -private: - // Set correct m_wlSubsurface position. - // - // This is defined only when using Wayland. - void UpdateSubsurfacePosition(); - - // Call eglCreatePlatformWindowSurface() when using EGL 1.5 or later, - // otherwise try eglCreatePlatformWindowSurfaceEXT() if it's available and - // fall back on eglCreateWindowSurface() otherwise. - // - // This function uses m_display and m_config which must be initialized - // before using it and should be passed either m_xwindow or m_wlEGLWindow - // depending on whether we are using X11 or Wayland. - EGLSurface CallCreatePlatformWindowSurface(void *window) const; - - - EGLConfig m_config = nullptr; - EGLDisplay m_display = nullptr; - EGLSurface m_surface = nullptr; - - unsigned long m_xwindow = 0; - wl_surface *m_wlSurface = nullptr; - wl_region *m_wlRegion = nullptr; - wl_subsurface *m_wlSubsurface = nullptr; - - bool m_readyToDraw = false; - bool m_swapIntervalSet = false; - - // the global/default versions of the above - static EGLConfig ms_glEGLConfig; - - // Called from GTK callbacks and needs access to private members. - friend void wxEGLUpdateGeometry(GtkWidget* widget, wxGLCanvasEGL* win); -}; - -// ---------------------------------------------------------------------------- -// wxGLApp -// ---------------------------------------------------------------------------- - -// this is used in wx/glcanvas.h, prevent it from defining a generic wxGLApp -#define wxGL_APP_DEFINED - -class WXDLLIMPEXP_GL wxGLApp : public wxGLAppBase -{ -public: - wxGLApp() : wxGLAppBase() { } - - // implement wxGLAppBase method - virtual bool InitGLVisual(const int *attribList) override - { - return wxGLCanvasEGL::InitDefaultConfig(attribList); - } - -#ifndef __WXGTK3__ - virtual void* GetXVisualInfo() override - { - return wxGLCanvasEGL::GetDefaultConfig(); - } -#endif // GTK < 3 - - // and override this wxApp method to clean up - virtual int OnExit() override - { - wxGLCanvasEGL::FreeDefaultConfig(); - - return wxGLAppBase::OnExit(); - } - -private: - wxDECLARE_DYNAMIC_CLASS(wxGLApp); -}; - -#endif // _WX_UNIX_GLEGL_H_ diff --git a/include/wx/unix/private/glcanvas.h b/include/wx/unix/private/glcanvas.h new file mode 100644 index 0000000000..0ec48635b2 --- /dev/null +++ b/include/wx/unix/private/glcanvas.h @@ -0,0 +1,162 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/glcontext.h +// Purpose: Base class for Unix-specific wxGLContext implementation +// Author: Vadim Zeitlin +// Created: 2025-12-07 +// Copyright: (c) 2025 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_PRIVATE_GLCANVAS_H_ +#define _WX_UNIX_PRIVATE_GLCANVAS_H_ + +// ---------------------------------------------------------------------------- +// wxGLContextImpl is used by wxGLContext to implement its functionality +// ---------------------------------------------------------------------------- + +class wxGLContextImpl +{ +public: + virtual ~wxGLContextImpl() = default; + + virtual bool SetCurrent(const wxGLCanvas& win) const = 0; + + bool IsOK() const { return m_isOk; } + +protected: + wxGLContextImpl() = default; + + // This is similar to wxGLContextBase::m_isOk and allows to keep the + // code from before the refactoring which introduced this class unchanged. + bool m_isOk = false; + + wxDECLARE_NO_COPY_CLASS(wxGLContextImpl); +}; + +// ---------------------------------------------------------------------------- +// wxGLCanvasUnixImpl: note that this is not a wxWindow-derived class +// ---------------------------------------------------------------------------- + +class wxGLCanvasUnixImpl +{ +public: + virtual ~wxGLCanvasUnixImpl() = default; + + virtual bool InitVisual(const wxGLAttributes& dispAttrs) = 0; + + virtual bool SwapBuffers() = 0; + + virtual void OnRealized() = 0; + + virtual bool HasWindow() const = 0; + + virtual void* GetXVisualInfo() const = 0; + +protected: + explicit wxGLCanvasUnixImpl(wxGLCanvasUnix* canvas) + : m_canvas(canvas) + { + } + + wxGLCanvasUnix* const m_canvas; + + wxDECLARE_NO_COPY_CLASS(wxGLCanvasUnixImpl); +}; + +// ---------------------------------------------------------------------------- +// wxGLBackend: used for creating implementation objects and implementing other +// non-member functions. +// ---------------------------------------------------------------------------- + +class wxGLBackend +{ +public: +#ifdef wxHAS_EGL + // This can be called only before calling Get() for the first time. + static void PreferGLX(); +#endif // wxHAS_EGL + + // Get the (sole) instance of this class. + static wxGLBackend& Get() + { + if ( !ms_instance ) + ms_instance = Init(); + + return *ms_instance; + } + + wxGLBackend(const wxGLBackend&) = delete; + wxGLBackend& operator=(const wxGLBackend&) = delete; + + virtual ~wxGLBackend() = default; + + // Factory functions for creating the implementation objects. + + virtual std::unique_ptr + CreateContextImpl(wxGLCanvas* win, + const wxGLContext* other, + const wxGLContextAttrs* ctxAttrs) = 0; + + virtual std::unique_ptr + CreateCanvasImpl(wxGLCanvasUnix* canvas) = 0; + + // Static functions of wxGLContext and wxGLCanvas. + virtual void ClearCurrentContext() = 0; + + virtual bool IsExtensionSupported(const char* extension) = 0; + + virtual bool IsDisplaySupported(const wxGLAttributes& dispAttrs) = 0; + + virtual int GetGLXVersion() = 0; + + virtual bool IsGLXMultiSampleAvailable() = 0; + + // wxGLApp functions implementation. + virtual bool InitDefaultVisualInfo(const int* attribList) = 0; + virtual void* GetDefaultVisualInfo() = 0; + virtual void FreeDefaultVisualInfo() = 0; + + // wxGLContextAttrs functions implementation. + virtual wxGLContextAttrs& CoreProfile(wxGLContextAttrs& attrs) = 0; + virtual wxGLContextAttrs& MajorVersion(wxGLContextAttrs& attrs, int val) = 0; + virtual wxGLContextAttrs& MinorVersion(wxGLContextAttrs& attrs, int val) = 0; + virtual wxGLContextAttrs& CompatibilityProfile(wxGLContextAttrs& attrs) = 0; + virtual wxGLContextAttrs& ForwardCompatible(wxGLContextAttrs& attrs) = 0; + virtual wxGLContextAttrs& ES2(wxGLContextAttrs& attrs) = 0; + virtual wxGLContextAttrs& DebugCtx(wxGLContextAttrs& attrs) = 0; + virtual wxGLContextAttrs& Robust(wxGLContextAttrs& attrs) = 0; + virtual wxGLContextAttrs& NoResetNotify(wxGLContextAttrs& attrs) = 0; + virtual wxGLContextAttrs& LoseOnReset(wxGLContextAttrs& attrs) = 0; + virtual wxGLContextAttrs& ResetIsolation(wxGLContextAttrs& attrs) = 0; + virtual wxGLContextAttrs& ReleaseFlush(wxGLContextAttrs& attrs, int val) = 0; + virtual wxGLContextAttrs& PlatformDefaults(wxGLContextAttrs& attrs) = 0; + + // wxGLAttributes functions implementation. + virtual wxGLAttributes& RGBA(wxGLAttributes& attrs) = 0; + virtual wxGLAttributes& BufferSize(wxGLAttributes& attrs, int val) = 0; + virtual wxGLAttributes& Level(wxGLAttributes& attrs, int val) = 0; + virtual wxGLAttributes& DoubleBuffer(wxGLAttributes& attrs) = 0; + virtual wxGLAttributes& Stereo(wxGLAttributes& attrs) = 0; + virtual wxGLAttributes& AuxBuffers(wxGLAttributes& attrs, int val) = 0; + virtual wxGLAttributes& MinRGBA(wxGLAttributes& attrs, int mRed, int mGreen, int mBlue, int mAlpha) = 0; + virtual wxGLAttributes& Depth(wxGLAttributes& attrs, int val) = 0; + virtual wxGLAttributes& Stencil(wxGLAttributes& attrs, int val) = 0; + virtual wxGLAttributes& MinAcumRGBA(wxGLAttributes& attrs, int mRed, int mGreen, int mBlue, int mAlpha) = 0; + virtual wxGLAttributes& PlatformDefaults(wxGLAttributes& attrs) = 0; + virtual wxGLAttributes& SampleBuffers(wxGLAttributes& attrs, int val) = 0; + virtual wxGLAttributes& Samplers(wxGLAttributes& attrs, int val) = 0; + virtual wxGLAttributes& FrameBuffersRGB(wxGLAttributes& attrs) = 0; + + // Both kinds of attributes are terminated in the same way. + virtual void EndList(wxGLAttribsBase& attrs) = 0; + +protected: + wxGLBackend() = default; + +private: + static wxGLBackend* Init(); + + static wxGLBackend* ms_instance; +}; + +#endif // _WX_UNIX_PRIVATE_GLCANVAS_H_ diff --git a/include/wx/unix/private/glegl.h b/include/wx/unix/private/glegl.h new file mode 100644 index 0000000000..2fabb31df4 --- /dev/null +++ b/include/wx/unix/private/glegl.h @@ -0,0 +1,188 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/glegl.h +// Purpose: wxGLContext EGL-based implementation +// Author: Vadim Zeitlin +// Created: 2025-12-07 +// Copyright: (c) 2025 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_PRIVATE_GLEGL_H_ +#define _WX_UNIX_PRIVATE_GLEGL_H_ + +#include "wx/unix/private/glcanvas.h" + +#include +#include + +struct wl_compositor; +struct wl_subcompositor; +struct wl_callback; +struct wl_egl_window; +struct wl_surface; +struct wl_region; +struct wl_subsurface; + +// ---------------------------------------------------------------------------- +// wxGLContextEGL +// ---------------------------------------------------------------------------- + +class wxGLContextEGL : public wxGLContextImpl +{ +public: + wxGLContextEGL(wxGLCanvas *win, + const wxGLContext *other = nullptr, + const wxGLContextAttrs *ctxAttrs = nullptr); + virtual ~wxGLContextEGL(); + + virtual bool SetCurrent(const wxGLCanvas& win) const override; + +private: + EGLContext m_glContext; +}; + +// ---------------------------------------------------------------------------- +// wxGLCanvasEGL +// ---------------------------------------------------------------------------- + +class wxGLCanvasEGL : public wxGLCanvasUnixImpl +{ +public: + explicit wxGLCanvasEGL(wxGLCanvasUnix* canvas) + : wxGLCanvasUnixImpl(canvas) + { + } + + virtual ~wxGLCanvasEGL() override; + + virtual bool InitVisual(const wxGLAttributes& dispAttrs) override; + + virtual bool SwapBuffers() override; + + virtual void OnRealized() override; + + virtual bool HasWindow() const override; + + virtual void* GetXVisualInfo() const override { return nullptr; } + + // implementation only from now on + // ------------------------------- + + void CreateWaylandSubsurface(); + void DestroyWaylandSubsurface(); + + EGLConfig GetEGLConfig() const { return m_config; } + EGLDisplay GetEGLDisplay() const { return m_display; } + EGLSurface GetEGLSurface() const { return m_surface; } + + static EGLDisplay GetDisplay(); + + // initializes EGLConfig + // + // returns nullptr if EGLConfig couldn't be initialized, otherwise caller + // is responsible for freeing the pointer + static EGLConfig InitConfig(const wxGLAttributes& dispAttrs); + + // Only called when using Wayland to indicate that we should be redrawn. + void OnWLFrameCallback(); + + wl_compositor *m_wlCompositor = nullptr; + wl_subcompositor *m_wlSubcompositor = nullptr; + wl_callback *m_wlFrameCallbackHandler = nullptr; + wl_egl_window *m_wlEGLWindow = nullptr; + +private: + // Set correct m_wlSubsurface position. + // + // This is defined only when using Wayland. + void UpdateSubsurfacePosition(); + + // Call eglCreatePlatformWindowSurface() when using EGL 1.5 or later, + // otherwise try eglCreatePlatformWindowSurfaceEXT() if it's available and + // fall back on eglCreateWindowSurface() otherwise. + // + // This function uses m_display and m_config which must be initialized + // before using it and should be passed either m_xwindow or m_wlEGLWindow + // depending on whether we are using X11 or Wayland. + EGLSurface CallCreatePlatformWindowSurface(void *window) const; + + + EGLConfig m_config = nullptr; + EGLDisplay m_display = nullptr; + EGLSurface m_surface = nullptr; + + unsigned long m_xwindow = 0; + wl_surface *m_wlSurface = nullptr; + wl_region *m_wlRegion = nullptr; + wl_subsurface *m_wlSubsurface = nullptr; + + bool m_readyToDraw = false; + bool m_swapIntervalSet = false; + + // Called from GTK callbacks and needs access to private members. + friend void wxEGLUpdateGeometry(GtkWidget* widget, wxGLCanvasEGL* win); +}; + +// ---------------------------------------------------------------------------- +// wxGLBackendEGL +// ---------------------------------------------------------------------------- + +class wxGLBackendEGL : public wxGLBackend +{ +public: + static wxGLBackend& Get(); + + wxGLBackendEGL() = default; + + std::unique_ptr + CreateContextImpl(wxGLCanvas* win, + const wxGLContext* other, + const wxGLContextAttrs* ctxAttrs) override; + + std::unique_ptr + CreateCanvasImpl(wxGLCanvasUnix* canvas) override; + + void ClearCurrentContext() override; + + bool IsExtensionSupported(const char* extension) override; + bool IsDisplaySupported(const wxGLAttributes& dispAttrs) override; + int GetGLXVersion() override; + bool IsGLXMultiSampleAvailable() override; + + bool InitDefaultVisualInfo(const int* attribList) override; + void* GetDefaultVisualInfo() override; + void FreeDefaultVisualInfo() override; + + wxGLContextAttrs& CoreProfile(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& MajorVersion(wxGLContextAttrs& attrs, int val) override; + wxGLContextAttrs& MinorVersion(wxGLContextAttrs& attrs, int val) override; + wxGLContextAttrs& CompatibilityProfile(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& ForwardCompatible(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& ES2(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& DebugCtx(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& Robust(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& NoResetNotify(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& LoseOnReset(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& ResetIsolation(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& ReleaseFlush(wxGLContextAttrs& attrs, int val) override; + wxGLContextAttrs& PlatformDefaults(wxGLContextAttrs& attrs) override; + + wxGLAttributes& RGBA(wxGLAttributes& attrs) override; + wxGLAttributes& BufferSize(wxGLAttributes& attrs, int val) override; + wxGLAttributes& Level(wxGLAttributes& attrs, int val) override; + wxGLAttributes& DoubleBuffer(wxGLAttributes& attrs) override; + wxGLAttributes& Stereo(wxGLAttributes& attrs) override; + wxGLAttributes& AuxBuffers(wxGLAttributes& attrs, int val) override; + wxGLAttributes& MinRGBA(wxGLAttributes& attrs, int mRed, int mGreen, int mBlue, int mAlpha) override; + wxGLAttributes& Depth(wxGLAttributes& attrs, int val) override; + wxGLAttributes& Stencil(wxGLAttributes& attrs, int val) override; + wxGLAttributes& MinAcumRGBA(wxGLAttributes& attrs, int mRed, int mGreen, int mBlue, int mAlpha) override; + wxGLAttributes& PlatformDefaults(wxGLAttributes& attrs) override; + wxGLAttributes& SampleBuffers(wxGLAttributes& attrs, int val) override; + wxGLAttributes& Samplers(wxGLAttributes& attrs, int val) override; + wxGLAttributes& FrameBuffersRGB(wxGLAttributes& attrs) override; + + void EndList(wxGLAttribsBase& attrs) override; +}; + +#endif // _WX_UNIX_PRIVATE_GLEGL_H_ diff --git a/include/wx/unix/private/glx11.h b/include/wx/unix/private/glx11.h new file mode 100644 index 0000000000..cd71fe7af7 --- /dev/null +++ b/include/wx/unix/private/glx11.h @@ -0,0 +1,131 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/glx11.h +// Purpose: wxGLContext GLX-based implementation for X11 +// Author: Vadim Zeitlin +// Created: 2025-12-07 +// Copyright: (c) 2025 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_PRIVATE_GLX11_H_ +#define _WX_UNIX_PRIVATE_GLX11_H_ + +#include "wx/unix/private/glcanvas.h" + +#include + +// ---------------------------------------------------------------------------- +// wxGLContextX11 +// ---------------------------------------------------------------------------- + +class wxGLContextX11 : public wxGLContextImpl +{ +public: + wxGLContextX11(wxGLCanvas *win, + const wxGLContext *other = nullptr, + const wxGLContextAttrs *ctxAttrs = nullptr); + virtual ~wxGLContextX11(); + + virtual bool SetCurrent(const wxGLCanvas& win) const override; + +private: + GLXContext m_glContext; +}; + +// ---------------------------------------------------------------------------- +// wxGLCanvasX11 +// ---------------------------------------------------------------------------- + +class wxGLCanvasX11 : public wxGLCanvasUnixImpl +{ +public: + explicit wxGLCanvasX11(wxGLCanvasUnix* canvas); + + virtual ~wxGLCanvasX11() override; + + virtual bool InitVisual(const wxGLAttributes& dispAttrs) override; + + virtual bool SwapBuffers() override; + + virtual void OnRealized() override { /* nothing to do here for GLX */ } + + virtual bool HasWindow() const override; + + virtual void* GetXVisualInfo() const override { return m_vi; } + + GLXFBConfig *GetGLXFBConfig() const { return m_fbc; } + + // initialize the global default GL visual, return false if matching visual + // not found + static bool InitDefaultVisualInfo(const int *attribList); + +private: + GLXFBConfig *m_fbc; + XVisualInfo* m_vi; + + bool m_swapIntervalSet = false; +}; + +// ---------------------------------------------------------------------------- +// wxGLBackendX11 +// ---------------------------------------------------------------------------- + +class wxGLBackendX11 : public wxGLBackend +{ +public: + static wxGLBackend& Get(); + + wxGLBackendX11() = default; + + std::unique_ptr + CreateContextImpl(wxGLCanvas* win, + const wxGLContext* other, + const wxGLContextAttrs* ctxAttrs) override; + + std::unique_ptr + CreateCanvasImpl(wxGLCanvasUnix* canvas) override; + + void ClearCurrentContext() override; + + bool IsExtensionSupported(const char* extension) override; + bool IsDisplaySupported(const wxGLAttributes& dispAttrs) override; + int GetGLXVersion() override; + bool IsGLXMultiSampleAvailable() override; + + bool InitDefaultVisualInfo(const int* attribList) override; + void* GetDefaultVisualInfo() override; + void FreeDefaultVisualInfo() override; + + wxGLContextAttrs& CoreProfile(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& MajorVersion(wxGLContextAttrs& attrs, int val) override; + wxGLContextAttrs& MinorVersion(wxGLContextAttrs& attrs, int val) override; + wxGLContextAttrs& CompatibilityProfile(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& ForwardCompatible(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& ES2(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& DebugCtx(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& Robust(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& NoResetNotify(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& LoseOnReset(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& ResetIsolation(wxGLContextAttrs& attrs) override; + wxGLContextAttrs& ReleaseFlush(wxGLContextAttrs& attrs, int val) override; + wxGLContextAttrs& PlatformDefaults(wxGLContextAttrs& attrs) override; + + wxGLAttributes& RGBA(wxGLAttributes& attrs) override; + wxGLAttributes& BufferSize(wxGLAttributes& attrs, int val) override; + wxGLAttributes& Level(wxGLAttributes& attrs, int val) override; + wxGLAttributes& DoubleBuffer(wxGLAttributes& attrs) override; + wxGLAttributes& Stereo(wxGLAttributes& attrs) override; + wxGLAttributes& AuxBuffers(wxGLAttributes& attrs, int val) override; + wxGLAttributes& MinRGBA(wxGLAttributes& attrs, int mRed, int mGreen, int mBlue, int mAlpha) override; + wxGLAttributes& Depth(wxGLAttributes& attrs, int val) override; + wxGLAttributes& Stencil(wxGLAttributes& attrs, int val) override; + wxGLAttributes& MinAcumRGBA(wxGLAttributes& attrs, int mRed, int mGreen, int mBlue, int mAlpha) override; + wxGLAttributes& PlatformDefaults(wxGLAttributes& attrs) override; + wxGLAttributes& SampleBuffers(wxGLAttributes& attrs, int val) override; + wxGLAttributes& Samplers(wxGLAttributes& attrs, int val) override; + wxGLAttributes& FrameBuffersRGB(wxGLAttributes& attrs) override; + + void EndList(wxGLAttribsBase& attrs) override; +}; + +#endif // _WX_UNIX_PRIVATE_GLX11_H_ diff --git a/include/wx/x11/glcanvas.h b/include/wx/x11/glcanvas.h index 200261970e..8a58b4b181 100644 --- a/include/wx/x11/glcanvas.h +++ b/include/wx/x11/glcanvas.h @@ -11,9 +11,9 @@ #ifndef _WX_GLCANVAS_H_ #define _WX_GLCANVAS_H_ -#include "wx/unix/glx11.h" +#include "wx/unix/glcanvas.h" -class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasX11 +class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasUnix { public: wxGLCanvas() = default; @@ -55,7 +55,7 @@ public: const int *attribList = nullptr, const wxPalette& palette = wxNullPalette); - // implement wxGLCanvasX11 methods + // implement wxGLCanvasUnix methods // -------------------------------- virtual unsigned long GetXWindow() const; diff --git a/interface/wx/glcanvas.h b/interface/wx/glcanvas.h index dcc0781059..14c88322a1 100644 --- a/interface/wx/glcanvas.h +++ b/interface/wx/glcanvas.h @@ -898,18 +898,6 @@ public: const wxPalette& palette = wxNullPalette); - /** - Re-creates EGLSurface. To be used after a reparent or other - changes that may invalidate the EGL drawing surface. - - Only available when wxUSE_GLCANVAS_EGL is enabled. - - @return @true if surface is successfully recreated - - @since 3.2.3 - */ - bool CreateSurface(); - /** Determines if a canvas having the specified attributes is available. This only applies for visual attributes, not rendering context attributes. @@ -945,6 +933,28 @@ public: */ static bool IsExtensionSupported(const char *extension); + /** + Prefer using GLX over other OpenGL implementations on Unix-like systems + where multiple implementations are available (such as GLX and EGL). + + This function is only available when `wxHAS_GLX` preprocessor symbol is + defined (which will be the case for wxGTK and wxX11 under Unix systems). + + It must be called before using any OpenGL functionality, which includes + not only creating wxGLCanvas but also checking for extension support or + creating attributes objects, doing it afterwards will trigger an assert + failure and have no other effect. + + Note that when using wxGTK with Wayland, calling this function will + have no effect anyhow as only EGL is supported in this case. + + Finally please note that the same effect can be achieved by setting the + environment variable `wx_opengl_egl=0` before starting the application. + + @since 3.3.2 + */ + static void PreferGLX(); + /** Sets the current colour for this window (using @c glcolor3f()), using the wxWidgets colour database to find a named colour. diff --git a/samples/opengl/cube/cube.cpp b/samples/opengl/cube/cube.cpp index f2b628ac9d..87c5c9ec9a 100644 --- a/samples/opengl/cube/cube.cpp +++ b/samples/opengl/cube/cube.cpp @@ -450,6 +450,7 @@ wxString glGetwxString(GLenum name) wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(wxID_NEW, MyFrame::OnNewWindow) EVT_MENU(NEW_STEREO_WINDOW, MyFrame::OnNewStereoWindow) + EVT_MENU(wxID_ABOUT, MyFrame::OnAbout) EVT_MENU(wxID_CLOSE, MyFrame::OnClose) wxEND_EVENT_TABLE() @@ -465,6 +466,8 @@ MyFrame::MyFrame( bool stereoWindow ) menu->Append(wxID_NEW); menu->Append(NEW_STEREO_WINDOW, "New Stereo Window"); menu->AppendSeparator(); + menu->Append(wxID_ABOUT, "&About...\tF1"); + menu->AppendSeparator(); menu->Append(wxID_CLOSE); wxMenuBar *menuBar = new wxMenuBar; menuBar->Append(menu, "&Cube"); @@ -492,6 +495,39 @@ MyFrame::MyFrame( bool stereoWindow ) } } +void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxString info = "This is the wxWidgets OpenGL Cube sample.\n\n"; + +#ifdef wxHAS_GLX + const int glxVersion = wxGLCanvasUnix::GetGLXVersion(); + if ( glxVersion == 0 ) + { + info += "Using EGL.\n\n"; + } + else + { + info += wxString::Format("Using GLX %d.%d.\n\n", + glxVersion / 10, glxVersion % 10); + } +#endif // wxHAS_GLX + + auto const getString = [](GLenum name) -> wxString + { + const GLubyte* const str = glGetString(name); + return wxString::FromUTF8(reinterpret_cast(str)); + }; + + info += wxString::Format("OpenGL version: %s\n", getString(GL_VERSION)); + info += wxString::Format("OpenGL vendor: %s\n", getString(GL_VENDOR)); + info += wxString::Format("OpenGL renderer: %s", getString(GL_RENDERER)); + + wxMessageBox(info, + "About wxWidgets OpenGL cube sample", + wxOK | wxICON_INFORMATION, + this); +} + void MyFrame::OnClose(wxCommandEvent& WXUNUSED(event)) { // true is to force the frame to close diff --git a/samples/opengl/cube/cube.h b/samples/opengl/cube/cube.h index 1ea4f0506d..5669992588 100644 --- a/samples/opengl/cube/cube.h +++ b/samples/opengl/cube/cube.h @@ -54,6 +54,7 @@ public: MyFrame(bool stereoWindow = false); private: + void OnAbout(wxCommandEvent& event); void OnClose(wxCommandEvent& event); void OnNewWindow(wxCommandEvent& event); void OnNewStereoWindow(wxCommandEvent& event); diff --git a/setup.h.in b/setup.h.in index f8635104d3..c34b935bf1 100644 --- a/setup.h.in +++ b/setup.h.in @@ -506,8 +506,6 @@ #define wxUSE_GLCANVAS 0 -#define wxUSE_GLCANVAS_EGL 0 - #define wxUSE_RICHTEXT 0 @@ -1138,6 +1136,9 @@ /* Define if locale_t is available */ #undef HAVE_LOCALE_T +/* Define if you have EGL support */ +#undef wxHAS_EGL + /* Define if you have inotify_xxx() functions. */ #undef wxHAS_INOTIFY diff --git a/setup.h_vms b/setup.h_vms index e8bed9a022..ca1acdd574 100644 --- a/setup.h_vms +++ b/setup.h_vms @@ -553,8 +553,6 @@ typedef pid_t GPid; #define wxUSE_GLCANVAS 1 -#define wxUSE_GLCANVAS_EGL 0 - #define wxUSE_RICHTEXT 1 #define wxUSE_CLIPBOARD 1 diff --git a/src/gtk/glcanvas.cpp b/src/gtk/glcanvas.cpp index 1ea762295b..fac1bb9393 100644 --- a/src/gtk/glcanvas.cpp +++ b/src/gtk/glcanvas.cpp @@ -42,7 +42,6 @@ static gboolean draw(GtkWidget* widget, cairo_t* cr, wxGLCanvas* win) // emission hook for "parent-set" //----------------------------------------------------------------------------- -#if !wxUSE_GLCANVAS_EGL extern "C" { static gboolean parent_set_hook(GSignalInvocationHint*, guint, const GValue* param_values, void* data) @@ -70,7 +69,6 @@ parent_set_hook(GSignalInvocationHint*, guint, const GValue* param_values, void* return true; } } -#endif //--------------------------------------------------------------------------- // wxGlCanvas @@ -111,12 +109,12 @@ static bool IsAvailable() #ifdef GDK_WINDOWING_WAYLAND if (wxGTKImpl::IsWayland(display)) { -#if wxUSE_GLCANVAS_EGL +#ifdef wxHAS_EGL return true; #else wxSafeShowMessage(_("Fatal Error"), _("This program wasn't compiled with EGL support required under Wayland, either\ninstall EGL libraries and rebuild or run it under X11 backend by setting\nenvironment variable GDK_BACKEND=x11 before starting your program.")); return false; -#endif // wxUSE_GLCANVAS_EGL +#endif // wxHAS_EGL/!wxHAS_EGL } #endif // GDK_WINDOWING_WAYLAND @@ -183,10 +181,11 @@ bool wxGLCanvas::Create(wxWindow *parent, // watch for the "parent-set" signal on m_wxwindow so we can set colormap // before m_wxwindow is realized (which will occur before // wxWindow::Create() returns if parent is already visible) -#if !wxUSE_GLCANVAS_EGL - unsigned sig_id = g_signal_lookup("parent-set", GTK_TYPE_WIDGET); - g_signal_add_emission_hook(sig_id, 0, parent_set_hook, this, nullptr); -#endif + if ( GetGLXVersion() ) + { + unsigned sig_id = g_signal_lookup("parent-set", GTK_TYPE_WIDGET); + g_signal_add_emission_hook(sig_id, 0, parent_set_hook, this, nullptr); + } wxWindow::Create( parent, id, pos, size, style, name ); #ifdef __WXGTK3__ @@ -217,11 +216,10 @@ unsigned long wxGLCanvas::GetXWindow() const void wxGLCanvas::GTKHandleRealized() { - BaseType::GTKHandleRealized(); + wxGLCanvasUnix::GTKHandleRealized(); + + CallOnRealized(); -#if wxUSE_GLCANVAS_EGL - CreateSurface(); -#endif SendSizeEvent(); } diff --git a/src/unix/glcanvas.cpp b/src/unix/glcanvas.cpp new file mode 100644 index 0000000000..0f4e3d9614 --- /dev/null +++ b/src/unix/glcanvas.cpp @@ -0,0 +1,356 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/unix/glcanvas.cpp +// Purpose: wxGLCanvas implementation common to wxGTK and wxX11 +// Author: Vadim Zeitlin +// Created: 2025-12-07 +// Copyright: (c) 2025 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#include "wx/sysopt.h" + +#include "wx/glcanvas.h" + +#include "wx/unix/private/glcanvas.h" +#include "wx/unix/private/glx11.h" +#ifdef wxHAS_EGL + #include "wx/unix/private/glegl.h" + + #ifdef __WXGTK3__ + #include "wx/gtk/private/wrapgdk.h" + #include "wx/gtk/private/backend.h" + #endif // __WXGTK3__ +#endif // wxHAS_EGL + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxGLContextAttrs: OpenGL rendering context attributes +// ---------------------------------------------------------------------------- + +wxGLContextAttrs& wxGLContextAttrs::CoreProfile() +{ + return wxGLBackend::Get().CoreProfile(*this); +} + +wxGLContextAttrs& wxGLContextAttrs::MajorVersion(int val) +{ + return wxGLBackend::Get().MajorVersion(*this, val); +} + +wxGLContextAttrs& wxGLContextAttrs::MinorVersion(int val) +{ + return wxGLBackend::Get().MinorVersion(*this, val); +} + +wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile() +{ + return wxGLBackend::Get().CompatibilityProfile(*this); +} + +wxGLContextAttrs& wxGLContextAttrs::ForwardCompatible() +{ + return wxGLBackend::Get().ForwardCompatible(*this); +} + +wxGLContextAttrs& wxGLContextAttrs::ES2() +{ + return wxGLBackend::Get().ES2(*this); +} + +wxGLContextAttrs& wxGLContextAttrs::DebugCtx() +{ + return wxGLBackend::Get().DebugCtx(*this); +} + +wxGLContextAttrs& wxGLContextAttrs::Robust() +{ + return wxGLBackend::Get().Robust(*this); +} + +wxGLContextAttrs& wxGLContextAttrs::NoResetNotify() +{ + return wxGLBackend::Get().NoResetNotify(*this); +} + +wxGLContextAttrs& wxGLContextAttrs::LoseOnReset() +{ + return wxGLBackend::Get().LoseOnReset(*this); +} + +wxGLContextAttrs& wxGLContextAttrs::ResetIsolation() +{ + return wxGLBackend::Get().ResetIsolation(*this); +} + +wxGLContextAttrs& wxGLContextAttrs::ReleaseFlush(int val) +{ + return wxGLBackend::Get().ReleaseFlush(*this, val); +} + +wxGLContextAttrs& wxGLContextAttrs::PlatformDefaults() +{ + return wxGLBackend::Get().PlatformDefaults(*this); +} + +void wxGLContextAttrs::EndList() +{ + wxGLBackend::Get().EndList(*this); +} + +// ---------------------------------------------------------------------------- +// wxGLAttributes: Visual/FBconfig attributes +// ---------------------------------------------------------------------------- + +wxGLAttributes& wxGLAttributes::RGBA() +{ + return wxGLBackend::Get().RGBA(*this); +} + +wxGLAttributes& wxGLAttributes::BufferSize(int val) +{ + return wxGLBackend::Get().BufferSize(*this, val); +} + +wxGLAttributes& wxGLAttributes::Level(int val) +{ + return wxGLBackend::Get().Level(*this, val); +} + +wxGLAttributes& wxGLAttributes::DoubleBuffer() +{ + return wxGLBackend::Get().DoubleBuffer(*this); +} + +wxGLAttributes& wxGLAttributes::Stereo() +{ + return wxGLBackend::Get().Stereo(*this); +} + +wxGLAttributes& wxGLAttributes::AuxBuffers(int val) +{ + return wxGLBackend::Get().AuxBuffers(*this, val); +} + +wxGLAttributes& wxGLAttributes::MinRGBA(int mRed, int mGreen, int mBlue, int mAlpha) +{ + return wxGLBackend::Get().MinRGBA(*this, mRed, mGreen, mBlue, mAlpha); +} + +wxGLAttributes& wxGLAttributes::Depth(int val) +{ + return wxGLBackend::Get().Depth(*this, val); +} + +wxGLAttributes& wxGLAttributes::Stencil(int val) +{ + return wxGLBackend::Get().Stencil(*this, val); +} + +wxGLAttributes& wxGLAttributes::MinAcumRGBA(int mRed, int mGreen, int mBlue, int mAlpha) +{ + return wxGLBackend::Get().MinAcumRGBA(*this, mRed, mGreen, mBlue, mAlpha); +} + +wxGLAttributes& wxGLAttributes::SampleBuffers(int val) +{ + return wxGLBackend::Get().SampleBuffers(*this, val); +} + +wxGLAttributes& wxGLAttributes::Samplers(int val) +{ + return wxGLBackend::Get().Samplers(*this, val); +} + +wxGLAttributes& wxGLAttributes::FrameBuffersRGB() +{ + return wxGLBackend::Get().FrameBuffersRGB(*this); +} + +void wxGLAttributes::EndList() +{ + wxGLBackend::Get().EndList(*this); +} + +wxGLAttributes& wxGLAttributes::PlatformDefaults() +{ + return wxGLBackend::Get().PlatformDefaults(*this); +} + +// ---------------------------------------------------------------------------- +// wxGLContext +// ---------------------------------------------------------------------------- + +wxIMPLEMENT_CLASS(wxGLContext, wxObject); + +wxGLBackend* wxGLBackend::ms_instance = nullptr; + +#ifdef wxHAS_EGL + +static bool wxGLBackendPreferGLX = false; + +/* static */ +void wxGLBackend::PreferGLX() +{ + wxASSERT_MSG( !ms_instance, + "PreferGLX() called too late and will have no effect" ); + + wxGLBackendPreferGLX = true; +} +#endif // wxHAS_EGL + +/* static */ +wxGLBackend* wxGLBackend::Init() +{ +#ifdef wxHAS_EGL + // Only EGL can be used when using Wayland, so ignore calls to PreferGLX() + // and system option in that case. + // + // It is unfortunate that we need to call wxGTK-specific functions from + // this code which is shared by wxGTK and wxX11, but there is no way to + // virtualize it, notably we can't do it at wxGLCanvas level because it may + // be already too late: for example, the backend has to be already + // available for attributes creation. +#if defined(__WXGTK3__) && defined(GDK_WINDOWING_WAYLAND) + if ( wxGTKImpl::IsWayland(gdk_display_get_default()) ) + return &wxGLBackendEGL::Get(); +#endif // GTK 3 with Wayland + + if ( !(wxGLBackendPreferGLX || wxSystemOptions::IsFalse("opengl.egl")) ) + return &wxGLBackendEGL::Get(); +#endif // wxHAS_EGL + + return &wxGLBackendX11::Get(); +} + +wxGLContext::wxGLContext(wxGLCanvas *win, + const wxGLContext *other, + const wxGLContextAttrs *ctxAttrs) + : m_impl(wxGLBackend::Get().CreateContextImpl(win, other, ctxAttrs)) +{ + m_isOk = m_impl && m_impl->IsOK(); +} + +wxGLContext::~wxGLContext() = default; + +bool wxGLContext::SetCurrent(const wxGLCanvas& win) const +{ + return IsOK() && m_impl->SetCurrent(win); +} + +/* static */ +void wxGLContextBase::ClearCurrent() +{ + wxGLBackend::Get().ClearCurrentContext(); +} + +// ---------------------------------------------------------------------------- +// wxGLCanvasUnix +// ---------------------------------------------------------------------------- + +wxGLCanvasUnix::wxGLCanvasUnix() + : m_impl(wxGLBackend::Get().CreateCanvasImpl(this)) +{ +} + +wxGLCanvasUnix::~wxGLCanvasUnix() = default; + +bool wxGLCanvasUnix::InitVisual(const wxGLAttributes& dispAttrs) +{ + return m_impl->InitVisual(dispAttrs); +} + +bool wxGLCanvasUnix::SwapBuffers() +{ + return m_impl->SwapBuffers(); +} + +bool wxGLCanvasUnix::IsShownOnScreen() const +{ + return m_impl->HasWindow() && wxGLCanvasBase::IsShownOnScreen(); +} + +void* wxGLCanvasUnix::GetXVisualInfo() const +{ + return m_impl->GetXVisualInfo(); +} + +void wxGLCanvasUnix::CallOnRealized() +{ + m_impl->OnRealized(); +} + +/* static */ +void wxGLCanvasUnix::PreferGLX() +{ +#ifdef wxHAS_EGL + wxGLBackend::PreferGLX(); +#endif // wxHAS_EGL +} + +/* static */ +int wxGLCanvasUnix::GetGLXVersion() +{ + return wxGLBackend::Get().GetGLXVersion(); +} + +/* static */ +bool wxGLCanvasUnix::IsGLXMultiSampleAvailable() +{ + return wxGLBackend::Get().IsGLXMultiSampleAvailable(); +} + +/* static */ +bool wxGLCanvasBase::IsExtensionSupported(const char *extension) +{ + return wxGLBackend::Get().IsExtensionSupported(extension); +} + +/* static */ +bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs) +{ + return wxGLBackend::Get().IsDisplaySupported(dispAttrs); +} + +/* static */ +bool wxGLCanvasBase::IsDisplaySupported(const int *attribList) +{ + wxGLAttributes dispAttrs; + ParseAttribList(attribList, dispAttrs); + + return IsDisplaySupported(dispAttrs); +} + +// ---------------------------------------------------------------------------- +// wxGLApp +// ---------------------------------------------------------------------------- + +bool wxGLApp::InitGLVisual(const int* attribList) +{ + return wxGLBackend::Get().InitDefaultVisualInfo(attribList); +} + +void* wxGLApp::GetXVisualInfo() +{ + return wxGLBackend::Get().GetDefaultVisualInfo(); +} + +int wxGLApp::OnExit() +{ + wxGLBackend::Get().FreeDefaultVisualInfo(); + + return wxGLAppBase::OnExit(); +} diff --git a/src/unix/glegl.cpp b/src/unix/glegl.cpp index 854b2b7d77..8927d205b7 100644 --- a/src/unix/glegl.cpp +++ b/src/unix/glegl.cpp @@ -1,6 +1,7 @@ /////////////////////////////////////////////////////////////////////////////// // Name: src/unix/glegl.cpp -// Purpose: code common to all EGL-based wxGLCanvas implementations +// Purpose: EGL-based wxGLCanvas implementation for wxGTK (this file is +// in src/unix subdirectory only for historical reasons) // Author: Scott Talbert // Created: 2017-12-26 // Copyright: (c) 2017 Scott Talbert @@ -18,9 +19,12 @@ // for compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" -#if wxUSE_GLCANVAS && wxUSE_GLCANVAS_EGL +#if wxUSE_GLCANVAS && defined(wxHAS_EGL) #include "wx/glcanvas.h" +#include "wx/unix/private/glegl.h" + +#include "wx/private/make_unique.h" #ifndef WX_PRECOMP #include "wx/log.h" @@ -32,9 +36,6 @@ #include #endif -#include -#include - #include namespace @@ -42,6 +43,9 @@ namespace constexpr const char* TRACE_EGL = "glegl"; +// It's ok to have this global variable because its ctor and dtor are trivial. +wxGLBackendEGL wxGLBackendEGL_instance; + // EGL version initialized by InitConfig(). EGLint gs_eglMajor = 0; EGLint gs_eglMinor = 0; @@ -53,238 +57,231 @@ EGLint gs_eglMinor = 0; // ---------------------------------------------------------------------------- // EGL specific values -wxGLContextAttrs& wxGLContextAttrs::CoreProfile() +wxGLContextAttrs& wxGLBackendEGL::CoreProfile(wxGLContextAttrs& attrs) { - AddAttribBits(EGL_CONTEXT_OPENGL_PROFILE_MASK, + attrs.AddAttribBits(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); - return *this; + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::MajorVersion(int val) +wxGLContextAttrs& wxGLBackendEGL::MajorVersion(wxGLContextAttrs& attrs, int val) { if ( val > 0 ) { - AddAttribute(EGL_CONTEXT_MAJOR_VERSION); - AddAttribute(val); + attrs.AddAttribute(EGL_CONTEXT_MAJOR_VERSION); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::MinorVersion(int val) +wxGLContextAttrs& wxGLBackendEGL::MinorVersion(wxGLContextAttrs& attrs, int val) { if ( val >= 0 ) { - AddAttribute(EGL_CONTEXT_MINOR_VERSION); - AddAttribute(val); + attrs.AddAttribute(EGL_CONTEXT_MINOR_VERSION); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile() +wxGLContextAttrs& wxGLBackendEGL::CompatibilityProfile(wxGLContextAttrs& attrs) { - AddAttribBits(EGL_CONTEXT_OPENGL_PROFILE_MASK, + attrs.AddAttribBits(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); - return *this; + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::ForwardCompatible() +wxGLContextAttrs& wxGLBackendEGL::ForwardCompatible(wxGLContextAttrs& attrs) { - AddAttribute(EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE); - AddAttribute(EGL_TRUE); - return *this; + attrs.AddAttribute(EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE); + attrs.AddAttribute(EGL_TRUE); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::ES2() +wxGLContextAttrs& wxGLBackendEGL::ES2(wxGLContextAttrs& attrs) { - useES = true; - return *this; + attrs.useES = true; + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::DebugCtx() +wxGLContextAttrs& wxGLBackendEGL::DebugCtx(wxGLContextAttrs& attrs) { - AddAttribute(EGL_CONTEXT_OPENGL_DEBUG); - AddAttribute(EGL_TRUE); - return *this; + attrs.AddAttribute(EGL_CONTEXT_OPENGL_DEBUG); + attrs.AddAttribute(EGL_TRUE); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::Robust() +wxGLContextAttrs& wxGLBackendEGL::Robust(wxGLContextAttrs& attrs) { - AddAttribute(EGL_CONTEXT_OPENGL_ROBUST_ACCESS); - AddAttribute(EGL_TRUE); - return *this; + attrs.AddAttribute(EGL_CONTEXT_OPENGL_ROBUST_ACCESS); + attrs.AddAttribute(EGL_TRUE); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::NoResetNotify() +wxGLContextAttrs& wxGLBackendEGL::NoResetNotify(wxGLContextAttrs& attrs) { - AddAttribute(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY); - AddAttribute(EGL_NO_RESET_NOTIFICATION); - return *this; + attrs.AddAttribute(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY); + attrs.AddAttribute(EGL_NO_RESET_NOTIFICATION); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::LoseOnReset() +wxGLContextAttrs& wxGLBackendEGL::LoseOnReset(wxGLContextAttrs& attrs) { - AddAttribute(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY); - AddAttribute(EGL_LOSE_CONTEXT_ON_RESET); - return *this; + attrs.AddAttribute(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY); + attrs.AddAttribute(EGL_LOSE_CONTEXT_ON_RESET); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::ResetIsolation() +wxGLContextAttrs& wxGLBackendEGL::ResetIsolation(wxGLContextAttrs& attrs) { - return *this; + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::ReleaseFlush(int) +wxGLContextAttrs& wxGLBackendEGL::ReleaseFlush(wxGLContextAttrs& attrs, int) { - return *this; + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::PlatformDefaults() +wxGLContextAttrs& wxGLBackendEGL::PlatformDefaults(wxGLContextAttrs& attrs) { - return *this; -} - -void wxGLContextAttrs::EndList() -{ - AddAttribute(EGL_NONE); + return attrs; } // ---------------------------------------------------------------------------- // wxGLAttributes: Visual/FBconfig attributes // ---------------------------------------------------------------------------- -wxGLAttributes& wxGLAttributes::RGBA() +wxGLAttributes& wxGLBackendEGL::RGBA(wxGLAttributes& attrs) { - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::BufferSize(int val) +wxGLAttributes& wxGLBackendEGL::BufferSize(wxGLAttributes& attrs, int val) { if ( val >= 0 ) { - AddAttribute(EGL_BUFFER_SIZE); - AddAttribute(val); + attrs.AddAttribute(EGL_BUFFER_SIZE); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::Level(int val) +wxGLAttributes& wxGLBackendEGL::Level(wxGLAttributes& attrs, int val) { - AddAttribute(EGL_LEVEL); - AddAttribute(val); - return *this; + attrs.AddAttribute(EGL_LEVEL); + attrs.AddAttribute(val); + return attrs; } -wxGLAttributes& wxGLAttributes::DoubleBuffer() +wxGLAttributes& wxGLBackendEGL::DoubleBuffer(wxGLAttributes& attrs) { - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::Stereo() +wxGLAttributes& wxGLBackendEGL::Stereo(wxGLAttributes& attrs) { - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::AuxBuffers(int) +wxGLAttributes& wxGLBackendEGL::AuxBuffers(wxGLAttributes& attrs, int) { - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::MinRGBA(int mRed, int mGreen, int mBlue, int mAlpha) +wxGLAttributes& wxGLBackendEGL::MinRGBA(wxGLAttributes& attrs, int mRed, int mGreen, int mBlue, int mAlpha) { if ( mRed >= 0) { - AddAttribute(EGL_RED_SIZE); - AddAttribute(mRed); + attrs.AddAttribute(EGL_RED_SIZE); + attrs.AddAttribute(mRed); } if ( mGreen >= 0) { - AddAttribute(EGL_GREEN_SIZE); - AddAttribute(mGreen); + attrs.AddAttribute(EGL_GREEN_SIZE); + attrs.AddAttribute(mGreen); } if ( mBlue >= 0) { - AddAttribute(EGL_BLUE_SIZE); - AddAttribute(mBlue); + attrs.AddAttribute(EGL_BLUE_SIZE); + attrs.AddAttribute(mBlue); } if ( mAlpha >= 0) { - AddAttribute(EGL_ALPHA_SIZE); - AddAttribute(mAlpha); + attrs.AddAttribute(EGL_ALPHA_SIZE); + attrs.AddAttribute(mAlpha); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::Depth(int val) +wxGLAttributes& wxGLBackendEGL::Depth(wxGLAttributes& attrs, int val) { if ( val >= 0 ) { - AddAttribute(EGL_DEPTH_SIZE); - AddAttribute(val); + attrs.AddAttribute(EGL_DEPTH_SIZE); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::Stencil(int val) +wxGLAttributes& wxGLBackendEGL::Stencil(wxGLAttributes& attrs, int val) { if ( val >= 0 ) { - AddAttribute(EGL_STENCIL_SIZE); - AddAttribute(val); + attrs.AddAttribute(EGL_STENCIL_SIZE); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::MinAcumRGBA(int, int, int, int) +wxGLAttributes& wxGLBackendEGL::MinAcumRGBA(wxGLAttributes& attrs, int, int, int, int) { - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::SampleBuffers(int val) +wxGLAttributes& wxGLBackendEGL::SampleBuffers(wxGLAttributes& attrs, int val) { if ( val >= 0 ) { - AddAttribute(EGL_SAMPLE_BUFFERS); - AddAttribute(val); + attrs.AddAttribute(EGL_SAMPLE_BUFFERS); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::Samplers(int val) +wxGLAttributes& wxGLBackendEGL::Samplers(wxGLAttributes& attrs, int val) { if ( val >= 0 ) { - AddAttribute(EGL_SAMPLES); - AddAttribute(val); + attrs.AddAttribute(EGL_SAMPLES); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::FrameBuffersRGB() +wxGLAttributes& wxGLBackendEGL::FrameBuffersRGB(wxGLAttributes& attrs) { - return *this; + return attrs; } -void wxGLAttributes::EndList() -{ - AddAttribute(EGL_NONE); -} - -wxGLAttributes& wxGLAttributes::PlatformDefaults() +wxGLAttributes& wxGLBackendEGL::PlatformDefaults(wxGLAttributes& attrs) { // No EGL specific values - return *this; + return attrs; +} + +void wxGLBackendEGL::EndList(wxGLAttribsBase& attrs) +{ + attrs.AddAttribute(EGL_NONE); } // ============================================================================ -// wxGLContext implementation +// wxGLContextEGL implementation // ============================================================================ -wxIMPLEMENT_CLASS(wxGLContext, wxObject); - -wxGLContext::wxGLContext(wxGLCanvas *win, - const wxGLContext *other, - const wxGLContextAttrs *ctxAttrs) +wxGLContextEGL::wxGLContextEGL(wxGLCanvas *win, + const wxGLContext *other, + const wxGLContextAttrs *ctxAttrs) : m_glContext(nullptr) { // Fall back to OpenGL context parameters set at wxGLCanvas ctor if any. @@ -301,11 +298,14 @@ wxGLContext::wxGLContext(wxGLCanvas *win, return; } - EGLConfig fbc = win->GetEGLConfig(); + EGLConfig fbc = static_cast(win->GetImpl())->GetEGLConfig(); wxCHECK_RET( fbc, "Invalid EGLConfig for OpenGL" ); + EGLContext otherCtx = EGL_NO_CONTEXT; + if ( other ) + otherCtx = static_cast(other->GetImpl())->m_glContext; m_glContext = eglCreateContext(wxGLCanvasEGL::GetDisplay(), fbc, - other ? other->m_glContext : EGL_NO_CONTEXT, + otherCtx, attrs.GetGLAttrs()); if ( !m_glContext ) @@ -314,28 +314,29 @@ wxGLContext::wxGLContext(wxGLCanvas *win, m_isOk = true; } -wxGLContext::~wxGLContext() +wxGLContextEGL::~wxGLContextEGL() { if ( !m_glContext ) return; if ( m_glContext == eglGetCurrentContext() ) - ClearCurrent(); + wxGLBackendEGL_instance.ClearCurrentContext(); eglDestroyContext(wxGLCanvasEGL::GetDisplay(), m_glContext); } -bool wxGLContext::SetCurrent(const wxGLCanvas& win) const +bool wxGLContextEGL::SetCurrent(const wxGLCanvas& win) const { if ( !m_glContext ) return false; - return eglMakeCurrent(win.GetEGLDisplay(), win.GetEGLSurface(), - win.GetEGLSurface(), m_glContext); + auto const winEGL = static_cast(win.GetImpl()); + + return eglMakeCurrent(winEGL->GetEGLDisplay(), winEGL->GetEGLSurface(), + winEGL->GetEGLSurface(), m_glContext); } -/* static */ -void wxGLContextBase::ClearCurrent() +void wxGLBackendEGL::ClearCurrentContext() { eglMakeCurrent(wxGLCanvasEGL::GetDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); @@ -421,8 +422,8 @@ void wxGLCanvasEGL::OnWLFrameCallback() m_readyToDraw = true; g_clear_pointer(&m_wlFrameCallbackHandler, wl_callback_destroy); - SendSizeEvent(); - gtk_widget_queue_draw(m_wxwindow); + m_canvas->SendSizeEvent(); + gtk_widget_queue_draw(m_canvas->m_wxwindow); #endif // GDK_WINDOWING_WAYLAND } @@ -439,7 +440,7 @@ void wxGLCanvasEGL::UpdateSubsurfacePosition() } int x, y; - gdk_window_get_origin(GTKGetDrawingWindow(), &x, &y); + gdk_window_get_origin(m_canvas->GTKGetDrawingWindow(), &x, &y); wl_subsurface_set_position(m_wlSubsurface, x, y); } @@ -449,8 +450,8 @@ void wxGLCanvasEGL::UpdateSubsurfacePosition() void wxEGLUpdateGeometry(GtkWidget* widget, wxGLCanvasEGL* win) { int scale = gtk_widget_get_scale_factor(widget); - wl_egl_window_resize(win->m_wlEGLWindow, win->m_width * scale, - win->m_height * scale, 0, 0); + wl_egl_window_resize(win->m_wlEGLWindow, win->m_canvas->m_width * scale, + win->m_canvas->m_height * scale, 0, 0); win->UpdateSubsurfacePosition(); @@ -561,7 +562,7 @@ EGLSurface wxGLCanvasEGL::CallCreatePlatformWindowSurface(void *window) const { s_extFuncInitialized = true; - if ( IsExtensionSupported("EGL_EXT_platform_base") ) + if ( wxGLBackendEGL_instance.IsExtensionSupported("EGL_EXT_platform_base") ) { s_eglCreatePlatformWindowSurfaceEXT = reinterpret_cast( eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT")); @@ -582,16 +583,16 @@ EGLSurface wxGLCanvasEGL::CallCreatePlatformWindowSurface(void *window) const } } -bool wxGLCanvasEGL::CreateSurface() +void wxGLCanvasEGL::OnRealized() { m_display = GetDisplay(); if ( m_display == EGL_NO_DISPLAY ) { wxFAIL_MSG("Unable to get EGL Display"); - return false; + return; } - GdkWindow *window = GTKGetDrawingWindow(); + GdkWindow *window = m_canvas->GTKGetDrawingWindow(); #ifdef GDK_WINDOWING_X11 if (wxGTKImpl::IsX11(window)) { @@ -612,7 +613,7 @@ bool wxGLCanvasEGL::CreateSurface() { // Already created (can happen when the canvas is un-realized then // re-realized, for example, when the canvas is re-parented) - return true; + return; } int w = gdk_window_get_width(window); @@ -624,7 +625,7 @@ bool wxGLCanvasEGL::CreateSurface() if ( !m_wlCompositor || !m_wlSubcompositor ) { wxFAIL_MSG("Invalid Wayland compositor or subcompositor"); - return false; + return; } m_wlSurface = wl_compositor_create_surface(m_wlCompositor); m_wlRegion = wl_compositor_create_region(m_wlCompositor); @@ -635,16 +636,18 @@ bool wxGLCanvasEGL::CreateSurface() h * scale); m_surface = CallCreatePlatformWindowSurface(m_wlEGLWindow); + GtkWidget* const widget = m_canvas->m_widget; + // We need to use "map-event" instead of "map" to ensure that the // widget's underlying Wayland surface has been created. // Otherwise, gdk_wayland_window_get_wl_surface may return nullptr, // for example when hiding then showing a window containing a canvas. - gtk_widget_add_events(m_widget, GDK_STRUCTURE_MASK); - g_signal_connect(m_widget, "map-event", + gtk_widget_add_events(widget, GDK_STRUCTURE_MASK); + g_signal_connect(widget, "map-event", G_CALLBACK(gtk_glcanvas_map_callback), this); // However, note the use of "unmap" instead of the later "unmap-event" // Not unmapping the canvas as soon as possible causes problems when reparenting - g_signal_connect(m_widget, "unmap", + g_signal_connect(widget, "unmap", G_CALLBACK(gtk_glcanvas_unmap_callback), this); // We connect to "size-allocate" to update the position of the @@ -653,9 +656,9 @@ bool wxGLCanvasEGL::CreateSurface() // "notify::scale-factor" to catch scale changes, which is especially // important initially, as we don't get a "size-allocate" with the // correct scale when the window is created. - g_signal_connect(m_widget, "size-allocate", + g_signal_connect(widget, "size-allocate", G_CALLBACK(gtk_glcanvas_size_callback), this); - g_signal_connect(m_widget, "notify::scale-factor", + g_signal_connect(widget, "notify::scale-factor", G_CALLBACK (gtk_glcanvas_scale_factor_notify), this); } #endif @@ -663,10 +666,8 @@ bool wxGLCanvasEGL::CreateSurface() if ( m_surface == EGL_NO_SURFACE ) { wxFAIL_MSG("Unable to create EGL surface"); - return false; + return; } - - return true; } wxGLCanvasEGL::~wxGLCanvasEGL() @@ -693,12 +694,12 @@ void wxGLCanvasEGL::CreateWaylandSubsurface() // Not ignoring either of the two scenarios will likely cause the subsurface // to be created twice, leading to a crash due to a Wayland protocol error // See https://github.com/wxWidgets/wxWidgets/issues/23961 - if ( !gtk_widget_get_mapped(m_widget) || m_wlSubsurface ) + if ( !gtk_widget_get_mapped(m_canvas->m_widget) || m_wlSubsurface ) { return; } - GdkWindow *window = GTKGetDrawingWindow(); + GdkWindow *window = m_canvas->GTKGetDrawingWindow(); struct wl_surface *surface = gdk_wayland_window_get_wl_surface(window); m_wlSubsurface = wl_subcompositor_get_subsurface(m_wlSubcompositor, @@ -727,12 +728,12 @@ void wxGLCanvasEGL::DestroyWaylandSubsurface() // working with GL attributes // ---------------------------------------------------------------------------- -/* static */ -bool wxGLCanvasBase::IsExtensionSupported(const char *extension) +bool wxGLBackendEGL::IsExtensionSupported(const char *extension) { EGLDisplay dpy = wxGLCanvasEGL::GetDisplay(); - return IsExtensionInList(eglQueryString(dpy, EGL_EXTENSIONS), extension); + return wxGLCanvasBase::IsExtensionInList(eglQueryString(dpy, EGL_EXTENSIONS), + extension); } @@ -837,44 +838,37 @@ EGLConfig wxGLCanvasEGL::InitConfig(const wxGLAttributes& dispAttrs) return configs.front(); } -/* static */ -bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs) +bool wxGLBackendEGL::IsDisplaySupported(const wxGLAttributes& dispAttrs) { return wxGLCanvasEGL::InitConfig(dispAttrs) != nullptr; } -/* static */ -bool wxGLCanvasBase::IsDisplaySupported(const int *attribList) -{ - wxGLAttributes dispAttrs; - ParseAttribList(attribList, dispAttrs); - - return IsDisplaySupported(dispAttrs); -} - // ---------------------------------------------------------------------------- // default visual management // ---------------------------------------------------------------------------- -EGLConfig wxGLCanvasEGL::ms_glEGLConfig = nullptr; +static EGLConfig wxDefaultEGLConfig = nullptr; -/* static */ -bool wxGLCanvasEGL::InitDefaultConfig(const int *attribList) +bool wxGLBackendEGL::InitDefaultVisualInfo(const int *attribList) { - FreeDefaultConfig(); wxGLAttributes dispAttrs; - ParseAttribList(attribList, dispAttrs); + wxGLCanvasBase::ParseAttribList(attribList, dispAttrs); - ms_glEGLConfig = InitConfig(dispAttrs); - return ms_glEGLConfig != nullptr; + wxDefaultEGLConfig = wxGLCanvasEGL::InitConfig(dispAttrs); + return wxDefaultEGLConfig != nullptr; } -/* static */ -void wxGLCanvasEGL::FreeDefaultConfig() +void wxGLBackendEGL::FreeDefaultVisualInfo() { - ms_glEGLConfig = nullptr; + wxDefaultEGLConfig = nullptr; } +void* wxGLBackendEGL::GetDefaultVisualInfo() +{ + return wxDefaultEGLConfig; +} + + // ---------------------------------------------------------------------------- // other GL methods // ---------------------------------------------------------------------------- @@ -908,13 +902,13 @@ bool wxGLCanvasEGL::SwapBuffers() } } - GdkWindow* const window = GTKGetDrawingWindow(); + GdkWindow* const window = m_canvas->GTKGetDrawingWindow(); #ifdef GDK_WINDOWING_X11 if (wxGTKImpl::IsX11(window)) { // TODO: We need to check if it's really shown on screen, i.e. if it's // not completely occluded even if it hadn't been explicitly hidden. - if ( !IsShownOnScreen() ) + if ( !m_canvas->IsShownOnScreen() ) { // Trying to draw on a hidden window is useless. wxLogTrace(TRACE_EGL, "Window %p is hidden, not drawing", this); @@ -940,15 +934,15 @@ bool wxGLCanvasEGL::SwapBuffers() return eglSwapBuffers(m_display, m_surface); } -bool wxGLCanvasEGL::IsShownOnScreen() const +bool wxGLCanvasEGL::HasWindow() const { wxDisplayInfo info = wxGetDisplayInfo(); switch ( info.type ) { case wxDisplayX11: - return GetXWindow() && wxGLCanvasBase::IsShownOnScreen(); + return m_canvas->GetXWindow(); case wxDisplayWayland: - return m_wlSubsurface && wxGLCanvasBase::IsShownOnScreen(); + return m_wlSubsurface; case wxDisplayNone: break; } @@ -956,5 +950,40 @@ bool wxGLCanvasEGL::IsShownOnScreen() const return false; } -#endif // wxUSE_GLCANVAS && wxUSE_GLCANVAS_EGL +// ---------------------------------------------------------------------------- +// wxGLBackendEGL +// ---------------------------------------------------------------------------- +/* static */ +wxGLBackend& wxGLBackendEGL::Get() +{ + return wxGLBackendEGL_instance; +} + +std::unique_ptr +wxGLBackendEGL::CreateContextImpl(wxGLCanvas* win, + const wxGLContext* other, + const wxGLContextAttrs* ctxAttrs) +{ + return std::make_unique(win, other, ctxAttrs); +} + +std::unique_ptr +wxGLBackendEGL::CreateCanvasImpl(wxGLCanvasUnix* canvas) +{ + return std::make_unique(canvas); +} + +int wxGLBackendEGL::GetGLXVersion() +{ + // EGL doesn't have GLX version. + return 0; +} + +bool wxGLBackendEGL::IsGLXMultiSampleAvailable() +{ + // EGL doesn't have GLX multisample extension. + return false; +} + +#endif // wxUSE_GLCANVAS && defined(wxHAS_EGL) diff --git a/src/unix/glx11.cpp b/src/unix/glx11.cpp index f867c0b053..74a35fefe8 100644 --- a/src/unix/glx11.cpp +++ b/src/unix/glx11.cpp @@ -18,17 +18,19 @@ // for compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" -#if wxUSE_GLCANVAS && !wxUSE_GLCANVAS_EGL +#if wxUSE_GLCANVAS #ifndef WX_PRECOMP #include "wx/log.h" #endif //WX_PRECOMP #include "wx/glcanvas.h" -#include +#include "wx/unix/private/glx11.h" #include "wx/unix/private/x11ptr.h" +#include "wx/private/make_unique.h" + // IRIX headers call this differently #ifdef __SGI__ #ifndef GLX_SAMPLE_BUFFERS_ARB @@ -131,6 +133,9 @@ namespace constexpr const char* TRACE_GLX = "glx"; +// It's ok to have this global variable because its ctor and dtor are trivial. +wxGLBackendX11 wxGLBackendX11_instance; + } // anonymous namespace // ---------------------------------------------------------------------------- @@ -138,121 +143,116 @@ constexpr const char* TRACE_GLX = "glx"; // ---------------------------------------------------------------------------- // GLX specific values -wxGLContextAttrs& wxGLContextAttrs::CoreProfile() +wxGLContextAttrs& wxGLBackendX11::CoreProfile(wxGLContextAttrs& attrs) { - AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB, + attrs.AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB); - SetNeedsARB(); - return *this; + attrs.SetNeedsARB(); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::MajorVersion(int val) +wxGLContextAttrs& wxGLBackendX11::MajorVersion(wxGLContextAttrs& attrs, int val) { if ( val > 0 ) { - AddAttribute(GLX_CONTEXT_MAJOR_VERSION_ARB); - AddAttribute(val); + attrs.AddAttribute(GLX_CONTEXT_MAJOR_VERSION_ARB); + attrs.AddAttribute(val); if ( val >= 3 ) - SetNeedsARB(); + attrs.SetNeedsARB(); } - return *this; + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::MinorVersion(int val) +wxGLContextAttrs& wxGLBackendX11::MinorVersion(wxGLContextAttrs& attrs, int val) { if ( val >= 0 ) { - AddAttribute(GLX_CONTEXT_MINOR_VERSION_ARB); - AddAttribute(val); + attrs.AddAttribute(GLX_CONTEXT_MINOR_VERSION_ARB); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile() +wxGLContextAttrs& wxGLBackendX11::CompatibilityProfile(wxGLContextAttrs& attrs) { - AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB, + attrs.AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); - SetNeedsARB(); - return *this; + attrs.SetNeedsARB(); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::ForwardCompatible() +wxGLContextAttrs& wxGLBackendX11::ForwardCompatible(wxGLContextAttrs& attrs) { - AddAttribBits(GLX_CONTEXT_FLAGS_ARB, + attrs.AddAttribBits(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB); - SetNeedsARB(); - return *this; + attrs.SetNeedsARB(); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::ES2() +wxGLContextAttrs& wxGLBackendX11::ES2(wxGLContextAttrs& attrs) { - AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB, + attrs.AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT); - SetNeedsARB(); - return *this; + attrs.SetNeedsARB(); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::DebugCtx() +wxGLContextAttrs& wxGLBackendX11::DebugCtx(wxGLContextAttrs& attrs) { - AddAttribBits(GLX_CONTEXT_FLAGS_ARB, + attrs.AddAttribBits(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB); - SetNeedsARB(); - return *this; + attrs.SetNeedsARB(); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::Robust() +wxGLContextAttrs& wxGLBackendX11::Robust(wxGLContextAttrs& attrs) { - AddAttribBits(GLX_CONTEXT_FLAGS_ARB, + attrs.AddAttribBits(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB); - SetNeedsARB(); - return *this; + attrs.SetNeedsARB(); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::NoResetNotify() +wxGLContextAttrs& wxGLBackendX11::NoResetNotify(wxGLContextAttrs& attrs) { - AddAttribute(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); - AddAttribute(GLX_NO_RESET_NOTIFICATION_ARB); - SetNeedsARB(); - return *this; + attrs.AddAttribute(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); + attrs.AddAttribute(GLX_NO_RESET_NOTIFICATION_ARB); + attrs.SetNeedsARB(); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::LoseOnReset() +wxGLContextAttrs& wxGLBackendX11::LoseOnReset(wxGLContextAttrs& attrs) { - AddAttribute(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); - AddAttribute(GLX_LOSE_CONTEXT_ON_RESET_ARB); - SetNeedsARB(); - return *this; + attrs.AddAttribute(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); + attrs.AddAttribute(GLX_LOSE_CONTEXT_ON_RESET_ARB); + attrs.SetNeedsARB(); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::ResetIsolation() +wxGLContextAttrs& wxGLBackendX11::ResetIsolation(wxGLContextAttrs& attrs) { - AddAttribBits(GLX_CONTEXT_FLAGS_ARB, + attrs.AddAttribBits(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_RESET_ISOLATION_BIT_ARB); - SetNeedsARB(); - return *this; + attrs.SetNeedsARB(); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::ReleaseFlush(int val) +wxGLContextAttrs& wxGLBackendX11::ReleaseFlush(wxGLContextAttrs& attrs, int val) { - AddAttribute(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB); + attrs.AddAttribute(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB); if ( val == 1 ) - AddAttribute(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + attrs.AddAttribute(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); else - AddAttribute(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); - SetNeedsARB(); - return *this; + attrs.AddAttribute(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + attrs.SetNeedsARB(); + return attrs; } -wxGLContextAttrs& wxGLContextAttrs::PlatformDefaults() +wxGLContextAttrs& wxGLBackendX11::PlatformDefaults(wxGLContextAttrs& attrs) { - renderTypeRGBA = true; - x11Direct = true; - return *this; -} - -void wxGLContextAttrs::EndList() -{ - AddAttribute(None); + attrs.renderTypeRGBA = true; + attrs.x11Direct = true; + return attrs; } // ---------------------------------------------------------------------------- @@ -272,173 +272,173 @@ void wxGLContextAttrs::EndList() // - Boolean attributes such as GLX_DOUBLEBUFFER don't take values in the // old version but must be followed by True or False in the new one. -wxGLAttributes& wxGLAttributes::RGBA() +wxGLAttributes& wxGLBackendX11::RGBA(wxGLAttributes& attrs) { - if ( wxGLCanvasX11::GetGLXVersion() >= 13 ) - AddAttribBits(GLX_RENDER_TYPE, GLX_RGBA_BIT); + if ( GetGLXVersion() >= 13 ) + attrs.AddAttribBits(GLX_RENDER_TYPE, GLX_RGBA_BIT); else - AddAttribute(GLX_RGBA); - return *this; + attrs.AddAttribute(GLX_RGBA); + return attrs; } -wxGLAttributes& wxGLAttributes::BufferSize(int val) +wxGLAttributes& wxGLBackendX11::BufferSize(wxGLAttributes& attrs, int val) { if ( val >= 0 ) { - AddAttribute(GLX_BUFFER_SIZE); - AddAttribute(val); + attrs.AddAttribute(GLX_BUFFER_SIZE); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::Level(int val) +wxGLAttributes& wxGLBackendX11::Level(wxGLAttributes& attrs, int val) { - AddAttribute(GLX_LEVEL); - AddAttribute(val); - return *this; + attrs.AddAttribute(GLX_LEVEL); + attrs.AddAttribute(val); + return attrs; } -wxGLAttributes& wxGLAttributes::DoubleBuffer() +wxGLAttributes& wxGLBackendX11::DoubleBuffer(wxGLAttributes& attrs) { - AddAttribute(GLX_DOUBLEBUFFER); - if ( wxGLCanvasX11::GetGLXVersion() >= 13 ) - AddAttribute(True); - return *this; + attrs.AddAttribute(GLX_DOUBLEBUFFER); + if ( GetGLXVersion() >= 13 ) + attrs.AddAttribute(True); + return attrs; } -wxGLAttributes& wxGLAttributes::Stereo() +wxGLAttributes& wxGLBackendX11::Stereo(wxGLAttributes& attrs) { - AddAttribute(GLX_STEREO); - if ( wxGLCanvasX11::GetGLXVersion() >= 13 ) - AddAttribute(True); - return *this; + attrs.AddAttribute(GLX_STEREO); + if ( GetGLXVersion() >= 13 ) + attrs.AddAttribute(True); + return attrs; } -wxGLAttributes& wxGLAttributes::AuxBuffers(int val) +wxGLAttributes& wxGLBackendX11::AuxBuffers(wxGLAttributes& attrs, int val) { if ( val >= 0 ) { - AddAttribute(GLX_AUX_BUFFERS); - AddAttribute(val); + attrs.AddAttribute(GLX_AUX_BUFFERS); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::MinRGBA(int mRed, int mGreen, int mBlue, int mAlpha) +wxGLAttributes& wxGLBackendX11::MinRGBA(wxGLAttributes& attrs, int mRed, int mGreen, int mBlue, int mAlpha) { if ( mRed >= 0) { - AddAttribute(GLX_RED_SIZE); - AddAttribute(mRed); + attrs.AddAttribute(GLX_RED_SIZE); + attrs.AddAttribute(mRed); } if ( mGreen >= 0) { - AddAttribute(GLX_GREEN_SIZE); - AddAttribute(mGreen); + attrs.AddAttribute(GLX_GREEN_SIZE); + attrs.AddAttribute(mGreen); } if ( mBlue >= 0) { - AddAttribute(GLX_BLUE_SIZE); - AddAttribute(mBlue); + attrs.AddAttribute(GLX_BLUE_SIZE); + attrs.AddAttribute(mBlue); } if ( mAlpha >= 0) { - AddAttribute(GLX_ALPHA_SIZE); - AddAttribute(mAlpha); + attrs.AddAttribute(GLX_ALPHA_SIZE); + attrs.AddAttribute(mAlpha); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::Depth(int val) +wxGLAttributes& wxGLBackendX11::Depth(wxGLAttributes& attrs, int val) { if ( val >= 0 ) { - AddAttribute(GLX_DEPTH_SIZE); - AddAttribute(val); + attrs.AddAttribute(GLX_DEPTH_SIZE); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::Stencil(int val) +wxGLAttributes& wxGLBackendX11::Stencil(wxGLAttributes& attrs, int val) { if ( val >= 0 ) { - AddAttribute(GLX_STENCIL_SIZE); - AddAttribute(val); + attrs.AddAttribute(GLX_STENCIL_SIZE); + attrs.AddAttribute(val); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::MinAcumRGBA(int mRed, int mGreen, int mBlue, int mAlpha) +wxGLAttributes& wxGLBackendX11::MinAcumRGBA(wxGLAttributes& attrs, int mRed, int mGreen, int mBlue, int mAlpha) { if ( mRed >= 0) { - AddAttribute(GLX_ACCUM_RED_SIZE); - AddAttribute(mRed); + attrs.AddAttribute(GLX_ACCUM_RED_SIZE); + attrs.AddAttribute(mRed); } if ( mGreen >= 0) { - AddAttribute(GLX_ACCUM_GREEN_SIZE); - AddAttribute(mGreen); + attrs.AddAttribute(GLX_ACCUM_GREEN_SIZE); + attrs.AddAttribute(mGreen); } if ( mBlue >= 0) { - AddAttribute(GLX_ACCUM_BLUE_SIZE); - AddAttribute(mBlue); + attrs.AddAttribute(GLX_ACCUM_BLUE_SIZE); + attrs.AddAttribute(mBlue); } if ( mAlpha >= 0) { - AddAttribute(GLX_ACCUM_ALPHA_SIZE); - AddAttribute(mAlpha); + attrs.AddAttribute(GLX_ACCUM_ALPHA_SIZE); + attrs.AddAttribute(mAlpha); } - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::SampleBuffers(int val) +wxGLAttributes& wxGLBackendX11::SampleBuffers(wxGLAttributes& attrs, int val) { #ifdef GLX_SAMPLE_BUFFERS_ARB - if ( val >= 0 && wxGLCanvasX11::IsGLXMultiSampleAvailable() ) + if ( val >= 0 && IsGLXMultiSampleAvailable() ) { - AddAttribute(GLX_SAMPLE_BUFFERS_ARB); - AddAttribute(val); + attrs.AddAttribute(GLX_SAMPLE_BUFFERS_ARB); + attrs.AddAttribute(val); } #endif - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::Samplers(int val) +wxGLAttributes& wxGLBackendX11::Samplers(wxGLAttributes& attrs, int val) { #ifdef GLX_SAMPLES_ARB - if ( val >= 0 && wxGLCanvasX11::IsGLXMultiSampleAvailable() ) + if ( val >= 0 && IsGLXMultiSampleAvailable() ) { - AddAttribute(GLX_SAMPLES_ARB); - AddAttribute(val); + attrs.AddAttribute(GLX_SAMPLES_ARB); + attrs.AddAttribute(val); } #endif - return *this; + return attrs; } -wxGLAttributes& wxGLAttributes::FrameBuffersRGB() +wxGLAttributes& wxGLBackendX11::FrameBuffersRGB(wxGLAttributes& attrs) { - AddAttribute(GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB); - AddAttribute(True); - return *this; + attrs.AddAttribute(GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB); + attrs.AddAttribute(True); + return attrs; } -void wxGLAttributes::EndList() -{ - AddAttribute(None); -} - -wxGLAttributes& wxGLAttributes::PlatformDefaults() +wxGLAttributes& wxGLBackendX11::PlatformDefaults(wxGLAttributes& attrs) { // No GLX specific values - return *this; + return attrs; +} + +void wxGLBackendX11::EndList(wxGLAttribsBase& attrs) +{ + attrs.AddAttribute(None); } // ============================================================================ -// wxGLContext implementation +// wxGLContextX11 implementation // ============================================================================ static bool MakeCurrent(GLXDrawable drawable, GLXContext context); @@ -451,13 +451,20 @@ static int CTXErrorHandler( Display* WXUNUSED(dpy), XErrorEvent* WXUNUSED(ev) ) return 0; } -wxIMPLEMENT_CLASS(wxGLContext, wxObject); - -wxGLContext::wxGLContext(wxGLCanvas *win, - const wxGLContext *other, - const wxGLContextAttrs *ctxAttrs) +wxGLContextX11::wxGLContextX11(wxGLCanvas *win, + const wxGLContext *otherCtx, + const wxGLContextAttrs *ctxAttrs) : m_glContext(nullptr) { + // We assume that all contexts in the program are of the same type, so the + // other context passed in must also be using wxGLContextX11. + auto const otherGLXContext = + otherCtx ? static_cast(otherCtx->GetImpl())->m_glContext + : None; + + // The window must also be of the appropriate type. + auto const winX11 = static_cast(win->GetImpl()); + const int* contextAttribs = nullptr; Bool x11Direct = True; int renderType = GLX_RGBA_TYPE; @@ -483,7 +490,7 @@ wxGLContext::wxGLContext(wxGLCanvas *win, m_isOk = false; Display* dpy = wxGetX11Display(); - XVisualInfo* vi = static_cast(win->GetXVisualInfo()); + XVisualInfo* vi = static_cast(winX11->GetXVisualInfo()); wxCHECK_RET( vi, "invalid visual for OpenGL" ); // We need to create a temporary context to get the @@ -491,7 +498,7 @@ wxGLContext::wxGLContext(wxGLCanvas *win, GLXContext tempContext = glXCreateContext(dpy, vi, nullptr, x11Direct); wxCHECK_RET(tempContext, "glXCreateContext failed" ); - GLXFBConfig* const fbc = win->GetGLXFBConfig(); + GLXFBConfig* const fbc = winX11->GetGLXFBConfig(); PFNGLXCREATECONTEXTATTRIBSARBPROC wx_glXCreateContextAttribsARB = 0; if (fbc) { @@ -516,7 +523,7 @@ wxGLContext::wxGLContext(wxGLCanvas *win, if ( wx_glXCreateContextAttribsARB ) { m_glContext = wx_glXCreateContextAttribsARB( dpy, fbc[0], - other ? other->m_glContext : None, + otherGLXContext, x11Direct, contextAttribs ); // Some old hardware may accept the use of this ARB, but may fail. @@ -535,13 +542,13 @@ wxGLContext::wxGLContext(wxGLCanvas *win, if (fbc) { m_glContext = glXCreateNewContext( dpy, fbc[0], renderType, - other ? other->m_glContext : None, + otherGLXContext, x11Direct ); } else // GLX <= 1.2 { m_glContext = glXCreateContext( dpy, vi, - other ? other->m_glContext : None, + otherGLXContext, x11Direct ); } } @@ -558,18 +565,18 @@ wxGLContext::wxGLContext(wxGLCanvas *win, XSetErrorHandler( oldHandler ); } -wxGLContext::~wxGLContext() +wxGLContextX11::~wxGLContextX11() { if ( !m_glContext ) return; if ( m_glContext == glXGetCurrentContext() ) - ClearCurrent(); + wxGLBackendX11_instance.ClearCurrentContext(); glXDestroyContext( wxGetX11Display(), m_glContext ); } -bool wxGLContext::SetCurrent(const wxGLCanvas& win) const +bool wxGLContextX11::SetCurrent(const wxGLCanvas& win) const { if ( !m_glContext ) return false; @@ -580,17 +587,11 @@ bool wxGLContext::SetCurrent(const wxGLCanvas& win) const return MakeCurrent(xid, m_glContext); } -/* static */ -void wxGLContextBase::ClearCurrent() -{ - MakeCurrent(None, nullptr); -} - // wrapper around glXMakeContextCurrent/glXMakeCurrent depending on GLX // version static bool MakeCurrent(GLXDrawable drawable, GLXContext context) { - if (wxGLCanvas::GetGLXVersion() >= 13) + if (wxGLBackendX11_instance.GetGLXVersion() >= 13) return glXMakeContextCurrent( wxGetX11Display(), drawable, drawable, context); else // GLX <= 1.2 doesn't have glXMakeContextCurrent() return glXMakeCurrent( wxGetX11Display(), drawable, context); @@ -610,7 +611,8 @@ static bool InitXVisualInfo( // initialization methods and dtor // ---------------------------------------------------------------------------- -wxGLCanvasX11::wxGLCanvasX11() +wxGLCanvasX11::wxGLCanvasX11(wxGLCanvasUnix* canvas) + : wxGLCanvasUnixImpl(canvas) { m_fbc = nullptr; m_vi = nullptr; @@ -641,18 +643,19 @@ wxGLCanvasX11::~wxGLCanvasX11() // working with GL attributes // ---------------------------------------------------------------------------- -/* static */ -bool wxGLCanvasBase::IsExtensionSupported(const char *extension) +bool wxGLBackendX11::IsExtensionSupported(const char *extension) { Display * const dpy = wxGetX11Display(); - return IsExtensionInList(glXQueryExtensionsString(dpy, DefaultScreen(dpy)), - extension); + return wxGLCanvasBase::IsExtensionInList + ( + glXQueryExtensionsString(dpy, DefaultScreen(dpy)), + extension + ); } -/* static */ -bool wxGLCanvasX11::IsGLXMultiSampleAvailable() +bool wxGLBackendX11::IsGLXMultiSampleAvailable() { static int s_isMultiSampleAvailable = -1; if ( s_isMultiSampleAvailable == -1 ) @@ -675,7 +678,7 @@ static bool InitXVisualInfo(const wxGLAttributes& dispAttrs, Display* dpy = wxGetX11Display(); - if (wxGLCanvasX11::GetGLXVersion() >= 13) + if (wxGLBackendX11_instance.GetGLXVersion() >= 13) { int returned; *pFBC = glXChooseFBConfig(dpy, DefaultScreen(dpy), attrsListGLX, &returned); @@ -701,8 +704,7 @@ static bool InitXVisualInfo(const wxGLAttributes& dispAttrs, return *pXVisual != nullptr; } -/* static */ -bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs) +bool wxGLBackendX11::IsDisplaySupported(const wxGLAttributes& dispAttrs) { wxX11Ptr fbc; wxX11Ptr vi; @@ -710,20 +712,11 @@ bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs) return InitXVisualInfo(dispAttrs, fbc.Out(), vi.Out()); } -/* static */ -bool wxGLCanvasBase::IsDisplaySupported(const int *attribList) -{ - wxGLAttributes dispAttrs; - ParseAttribList(attribList, dispAttrs); - - return IsDisplaySupported(dispAttrs); -} - // ---------------------------------------------------------------------------- // default visual management // ---------------------------------------------------------------------------- -static void FreeDefaultVisualInfo() +void wxGLBackendX11::FreeDefaultVisualInfo() { if (gs_glFBCInfo) { @@ -737,22 +730,25 @@ static void FreeDefaultVisualInfo() } } -/* static */ -bool wxGLCanvasX11::InitDefaultVisualInfo(const int *attribList) +bool wxGLBackendX11::InitDefaultVisualInfo(const int* attribList) { FreeDefaultVisualInfo(); wxGLAttributes dispAttrs; - ParseAttribList(attribList, dispAttrs); + wxGLCanvasBase::ParseAttribList(attribList, dispAttrs); return InitXVisualInfo(dispAttrs, &gs_glFBCInfo, &gs_glVisualInfo); } +void* wxGLBackendX11::GetDefaultVisualInfo() +{ + return gs_glVisualInfo; +} + // ---------------------------------------------------------------------------- // other GL methods // ---------------------------------------------------------------------------- -/* static */ -int wxGLCanvasX11::GetGLXVersion() +int wxGLBackendX11::GetGLXVersion() { static int s_glxVersion = 0; if ( s_glxVersion == 0 ) @@ -806,7 +802,7 @@ void wxGLSetSwapInterval(Display* dpy, GLXDrawable drawable, int interval) bool wxGLCanvasX11::SwapBuffers() { - const Window xid = GetXWindow(); + const Window xid = m_canvas->GetXWindow(); wxCHECK2_MSG( xid, return false, wxT("window must be shown") ); const auto dpy = wxGetX11Display(); @@ -826,30 +822,38 @@ bool wxGLCanvasX11::SwapBuffers() return true; } -bool wxGLCanvasX11::IsShownOnScreen() const +bool wxGLCanvasX11::HasWindow() const { - return GetXWindow() && wxGLCanvasBase::IsShownOnScreen(); + return m_canvas->GetXWindow(); } // ---------------------------------------------------------------------------- -// wxGLApp +// wxGLBackendX11 // ---------------------------------------------------------------------------- -bool wxGLApp::InitGLVisual(const int* attribList) +/* static */ +wxGLBackend& wxGLBackendX11::Get() { - return wxGLCanvasX11::InitDefaultVisualInfo(attribList); + return wxGLBackendX11_instance; } -void* wxGLApp::GetXVisualInfo() +std::unique_ptr +wxGLBackendX11::CreateContextImpl(wxGLCanvas* win, + const wxGLContext* other, + const wxGLContextAttrs* ctxAttrs) { - return gs_glVisualInfo; + return std::make_unique(win, other, ctxAttrs); } -int wxGLApp::OnExit() +std::unique_ptr +wxGLBackendX11::CreateCanvasImpl(wxGLCanvasUnix* canvas) { - FreeDefaultVisualInfo(); + return std::make_unique(canvas); +} - return wxGLAppBase::OnExit(); +void wxGLBackendX11::ClearCurrentContext() +{ + MakeCurrent(None, nullptr); } #endif // wxUSE_GLCANVAS