diff --git a/Makefile.in b/Makefile.in index 4b0c2dd420..54fbec3abd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2292,9 +2292,11 @@ COND_TOOLKIT_MSW_WEBVIEW_HDR_PLATFORM = \ @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2@OPENGL_HDR_PLATFORM \ @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2@ = wx/gtk/glcanvas.h wx/unix/glx11.h @COND_TOOLKIT_GTK_TOOLKIT_VERSION_3@OPENGL_HDR_PLATFORM \ -@COND_TOOLKIT_GTK_TOOLKIT_VERSION_3@ = wx/gtk/glcanvas.h wx/unix/glx11.h +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_3@ = wx/gtk/glcanvas.h wx/unix/glegl.h \ +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_3@ wx/unix/glx11.h @COND_TOOLKIT_GTK_TOOLKIT_VERSION_4@OPENGL_HDR_PLATFORM \ -@COND_TOOLKIT_GTK_TOOLKIT_VERSION_4@ = wx/gtk/glcanvas.h wx/unix/glx11.h +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_4@ = wx/gtk/glcanvas.h wx/unix/glegl.h \ +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_4@ wx/unix/glx11.h @COND_TOOLKIT_MOTIF@OPENGL_HDR_PLATFORM = wx/x11/glcanvas.h wx/unix/glx11.h @COND_TOOLKIT_MSW@OPENGL_HDR_PLATFORM = wx/msw/glcanvas.h @COND_TOOLKIT_OSX_COCOA@OPENGL_HDR_PLATFORM = wx/osx/glcanvas.h @@ -13088,10 +13090,12 @@ 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_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@__OPENGL_SRC_PLATFORM_OBJECTS \ -@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@ = gldll_glx11.o \ +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@ = gldll_glegl.o \ +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@ gldll_glx11.o \ @COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@ gldll_gtk_glcanvas.o @COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@__OPENGL_SRC_PLATFORM_OBJECTS \ -@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ = gldll_glx11.o \ +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ = gldll_glegl.o \ +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ gldll_glx11.o \ @COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ gldll_gtk_glcanvas.o @COND_TOOLKIT_COCOA@__OPENGL_SRC_PLATFORM_OBJECTS = \ @COND_TOOLKIT_COCOA@ gldll_src_cocoa_glcanvas.o @@ -13131,10 +13135,12 @@ 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_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@__OPENGL_SRC_PLATFORM_OBJECTS_1 \ -@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@ = gllib_glx11.o \ +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@ = gllib_glegl.o \ +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@ gllib_glx11.o \ @COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@ gllib_gtk_glcanvas.o @COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@__OPENGL_SRC_PLATFORM_OBJECTS_1 \ -@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ = gllib_glx11.o \ +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ = gllib_glegl.o \ +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ gllib_glx11.o \ @COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ gllib_gtk_glcanvas.o @COND_TOOLKIT_COCOA@__OPENGL_SRC_PLATFORM_OBJECTS_1 = \ @COND_TOOLKIT_COCOA@ gllib_src_cocoa_glcanvas.o @@ -36732,6 +36738,12 @@ gldll_msw_glcanvas.o: $(srcdir)/src/msw/glcanvas.cpp $(GLDLL_ODEP) @COND_TOOLKIT_OSX_IPHONE@gldll_glcanvas_osx.o: $(srcdir)/src/osx/glcanvas_osx.cpp $(GLDLL_ODEP) @COND_TOOLKIT_OSX_IPHONE@ $(CXXC) -c -o $@ $(GLDLL_CXXFLAGS) $(srcdir)/src/osx/glcanvas_osx.cpp +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@gldll_glegl.o: $(srcdir)/src/unix/glegl.cpp $(GLDLL_ODEP) +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ $(CXXC) -c -o $@ $(GLDLL_CXXFLAGS) $(srcdir)/src/unix/glegl.cpp + +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@gldll_glegl.o: $(srcdir)/src/unix/glegl.cpp $(GLDLL_ODEP) +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@ $(CXXC) -c -o $@ $(GLDLL_CXXFLAGS) $(srcdir)/src/unix/glegl.cpp + @COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@gldll_glx11.o: $(srcdir)/src/unix/glx11.cpp $(GLDLL_ODEP) @COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ $(CXXC) -c -o $@ $(GLDLL_CXXFLAGS) $(srcdir)/src/unix/glx11.cpp @@ -36792,6 +36804,12 @@ gllib_msw_glcanvas.o: $(srcdir)/src/msw/glcanvas.cpp $(GLLIB_ODEP) @COND_TOOLKIT_OSX_IPHONE@gllib_glcanvas_osx.o: $(srcdir)/src/osx/glcanvas_osx.cpp $(GLLIB_ODEP) @COND_TOOLKIT_OSX_IPHONE@ $(CXXC) -c -o $@ $(GLLIB_CXXFLAGS) $(srcdir)/src/osx/glcanvas_osx.cpp +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@gllib_glegl.o: $(srcdir)/src/unix/glegl.cpp $(GLLIB_ODEP) +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ $(CXXC) -c -o $@ $(GLLIB_CXXFLAGS) $(srcdir)/src/unix/glegl.cpp + +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@gllib_glegl.o: $(srcdir)/src/unix/glegl.cpp $(GLLIB_ODEP) +@COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_3@ $(CXXC) -c -o $@ $(GLLIB_CXXFLAGS) $(srcdir)/src/unix/glegl.cpp + @COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@gllib_glx11.o: $(srcdir)/src/unix/glx11.cpp $(GLLIB_ODEP) @COND_PLATFORM_WIN32_0_TOOLKIT_GTK_TOOLKIT_VERSION_4@ $(CXXC) -c -o $@ $(GLLIB_CXXFLAGS) $(srcdir)/src/unix/glx11.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index b5c240db5f..983df6483b 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -3191,10 +3191,12 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/osx/iphone/glcanvas.mm src/osx/glcanvas_osx.cpp src/cocoa/glcanvas.mm + src/unix/glegl.cpp src/unix/glx11.cpp src/gtk/glcanvas.cpp + src/unix/glegl.cpp src/unix/glx11.cpp src/gtk/glcanvas.cpp @@ -3222,10 +3224,12 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/cocoa/glcanvas.h wx/gtk/glcanvas.h + wx/unix/glegl.h wx/unix/glx11.h wx/gtk/glcanvas.h + wx/unix/glegl.h wx/unix/glx11.h diff --git a/build/cmake/files.cmake b/build/cmake/files.cmake index f3db68b0bd..e60edd09fa 100644 --- a/build/cmake/files.cmake +++ b/build/cmake/files.cmake @@ -3036,11 +3036,13 @@ set(OPENGL_MSW_HDR set(OPENGL_GTK_SRC src/gtk/glcanvas.cpp src/unix/glx11.cpp + src/unix/glegl.cpp ) set(OPENGL_GTK_HDR wx/gtk/glcanvas.h wx/unix/glx11.h + wx/unix/glegl.h ) set(OPENGL_OSX_COCOA_SRC diff --git a/build/cmake/init.cmake b/build/cmake/init.cmake index d013e92a5a..5487ad92cf 100644 --- a/build/cmake/init.cmake +++ b/build/cmake/init.cmake @@ -385,6 +385,9 @@ if(wxUSE_GUI) set(OPENGL_LIBRARIES "-framework OpenGLES" "-framework QuartzCore") else() find_package(OpenGL) + if(WXGTK3 AND OpenGL_EGL_FOUND) + set(wxUSE_GLCANVAS_EGL ON) + endif() endif() if(NOT OPENGL_FOUND) message(WARNING "opengl not found, wxGLCanvas won't be available") diff --git a/build/cmake/setup.h.in b/build/cmake/setup.h.in index 77f5c8111e..b71e097360 100644 --- a/build/cmake/setup.h.in +++ b/build/cmake/setup.h.in @@ -549,6 +549,8 @@ #cmakedefine01 wxUSE_GLCANVAS +#cmakedefine01 wxUSE_GLCANVAS_EGL + #cmakedefine01 wxUSE_RICHTEXT diff --git a/build/files b/build/files index 759ab54db1..490e4dfb7f 100644 --- a/build/files +++ b/build/files @@ -2973,10 +2973,12 @@ OPENGL_MSW_SRC = OPENGL_GTK_HDR = wx/gtk/glcanvas.h + wx/unix/glegl.h wx/unix/glx11.h OPENGL_GTK_SRC = src/gtk/glcanvas.cpp + src/unix/glegl.cpp src/unix/glx11.cpp OPENGL_MSW_HDR = diff --git a/configure b/configure index 968e728974..93c0f23a50 100755 --- a/configure +++ b/configure @@ -953,6 +953,8 @@ CXXFLAGS_VISIBILITY CFLAGS_VISIBILITY MesaGL_LIBS MesaGL_CFLAGS +EGL_LIBS +EGL_CFLAGS GLU_LIBS GLU_CFLAGS GL_LIBS @@ -1029,7 +1031,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -1398,6 +1399,8 @@ GL_CFLAGS GL_LIBS GLU_CFLAGS GLU_LIBS +EGL_CFLAGS +EGL_LIBS MesaGL_CFLAGS MesaGL_LIBS LIBSECRET_CFLAGS @@ -1458,7 +1461,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1711,15 +1713,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1857,7 +1850,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -2010,7 +2003,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -2413,6 +2405,8 @@ Some influential environment variables: GL_LIBS linker flags for GL, overriding pkg-config GLU_CFLAGS C compiler flags for GLU, overriding pkg-config GLU_LIBS linker flags for GLU, overriding pkg-config + EGL_CFLAGS C compiler flags for EGL, overriding pkg-config + EGL_LIBS linker flags for EGL, overriding pkg-config MesaGL_CFLAGS C compiler flags for MesaGL, overriding pkg-config MesaGL_LIBS linker flags for MesaGL, overriding pkg-config @@ -28269,6 +28263,90 @@ fi found_gl=1 OPENGL_LIBS="-lGL -lGLU" + + if test "$WXGTK3" = 1; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for EGL" >&5 +$as_echo_n "checking for EGL... " >&6; } + +if test -n "$PKG_CONFIG"; then + if test -n "$EGL_CFLAGS"; then + pkg_cv_EGL_CFLAGS="$EGL_CFLAGS" + else + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"egl >= 1.5\""; } >&5 + ($PKG_CONFIG --exists --print-errors "egl >= 1.5") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_EGL_CFLAGS=`$PKG_CONFIG --cflags "egl >= 1.5" 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi +if test -n "$PKG_CONFIG"; then + if test -n "$EGL_LIBS"; then + pkg_cv_EGL_LIBS="$EGL_LIBS" + else + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"egl >= 1.5\""; } >&5 + ($PKG_CONFIG --exists --print-errors "egl >= 1.5") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_EGL_LIBS=`$PKG_CONFIG --libs "egl >= 1.5" 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + EGL_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "egl >= 1.5"` + else + EGL_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "egl >= 1.5"` + fi + # Put the nasty error message in config.log where it belongs + echo "$EGL_PKG_ERRORS" >&5 + + + { $as_echo "$as_me:${as_lineno-$LINENO}: EGL 1.5+ not available. Will use GLX." >&5 +$as_echo "$as_me: EGL 1.5+ not available. Will use GLX." >&6;} + + +elif test $pkg_failed = untried; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: EGL 1.5+ not available. Will use GLX." >&5 +$as_echo "$as_me: EGL 1.5+ not available. Will use GLX." >&6;} + + +else + EGL_CFLAGS=$pkg_cv_EGL_CFLAGS + EGL_LIBS=$pkg_cv_EGL_LIBS + { $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 + + +fi + fi fi fi diff --git a/configure.in b/configure.in index 37622d6d51..fd7d7d9caf 100644 --- a/configure.in +++ b/configure.in @@ -3793,6 +3793,18 @@ if test "$wxUSE_OPENGL" = "yes" -o "$wxUSE_OPENGL" = "auto"; then found_gl=1 OPENGL_LIBS="-lGL -lGLU" + + if test "$WXGTK3" = 1; then + PKG_CHECK_MODULES(EGL, [egl >= 1.5], + [ + OPENGL_LIBS="$OPENGL_LIBS $EGL_LIBS" + AC_DEFINE(wxUSE_GLCANVAS_EGL) + ], + [ + AC_MSG_NOTICE([EGL 1.5+ not available. Will use GLX.]) + ] + ) + fi fi fi diff --git a/include/wx/android/setup.h b/include/wx/android/setup.h index 197a0af802..fcf2d989d2 100644 --- a/include/wx/android/setup.h +++ b/include/wx/android/setup.h @@ -1386,6 +1386,13 @@ // 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. +// +// Default is 0. +// +#define wxUSE_GLCANVAS_EGL 0 + // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/gtk/glcanvas.h b/include/wx/gtk/glcanvas.h index ff0eddd141..a4aaffb9ad 100644 --- a/include/wx/gtk/glcanvas.h +++ b/include/wx/gtk/glcanvas.h @@ -11,15 +11,23 @@ #ifndef _WX_GLCANVAS_H_ #define _WX_GLCANVAS_H_ -#include "wx/unix/glx11.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 //--------------------------------------------------------------------------- // wxGLCanvas //--------------------------------------------------------------------------- -class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasX11 +class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasImpl { - typedef wxGLCanvasX11 BaseType; + typedef wxGLCanvasImpl BaseType; public: wxGLCanvas(wxWindow *parent, const wxGLAttributes& dispAttrs, @@ -64,7 +72,7 @@ public: // -------------------------------- virtual unsigned long GetXWindow() const wxOVERRIDE; - + void* GetNativeWindow() const; // deprecated methods // ------------------ diff --git a/include/wx/gtk/setup0.h b/include/wx/gtk/setup0.h index e09a86bfdf..1a8dc8f40a 100644 --- a/include/wx/gtk/setup0.h +++ b/include/wx/gtk/setup0.h @@ -1387,6 +1387,13 @@ // 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. +// +// Default is 0. +// +#define wxUSE_GLCANVAS_EGL 0 + // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/motif/setup0.h b/include/wx/motif/setup0.h index cf7268d1a5..1fb42dca02 100644 --- a/include/wx/motif/setup0.h +++ b/include/wx/motif/setup0.h @@ -1387,6 +1387,13 @@ // 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. +// +// Default is 0. +// +#define wxUSE_GLCANVAS_EGL 0 + // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/msw/setup0.h b/include/wx/msw/setup0.h index 0905003ab1..e253cc3cbd 100644 --- a/include/wx/msw/setup0.h +++ b/include/wx/msw/setup0.h @@ -1387,6 +1387,13 @@ // 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. +// +// Default is 0. +// +#define wxUSE_GLCANVAS_EGL 0 + // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/osx/setup0.h b/include/wx/osx/setup0.h index 04636ec158..a5ff4f93c7 100644 --- a/include/wx/osx/setup0.h +++ b/include/wx/osx/setup0.h @@ -1393,6 +1393,13 @@ // 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. +// +// 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 623ed70752..c24b0abf48 100644 --- a/include/wx/setup_inc.h +++ b/include/wx/setup_inc.h @@ -1383,6 +1383,14 @@ // 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/setup0.h b/include/wx/univ/setup0.h index a8ab9b665f..a7eee09ad7 100644 --- a/include/wx/univ/setup0.h +++ b/include/wx/univ/setup0.h @@ -1386,6 +1386,13 @@ // 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. +// +// Default is 0. +// +#define wxUSE_GLCANVAS_EGL 0 + // wxRichTextCtrl allows editing of styled text. // // Default is 1. diff --git a/include/wx/unix/glegl.h b/include/wx/unix/glegl.h new file mode 100644 index 0000000000..ccdd302e36 --- /dev/null +++ b/include/wx/unix/glegl.h @@ -0,0 +1,179 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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 = NULL, + const wxGLContextAttrs *ctxAttrs = NULL); + virtual ~wxGLContext(); + + virtual bool SetCurrent(const wxGLCanvas& win) const wxOVERRIDE; + +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(); + + // initializes EGLConfig corresponding to the given attributes + bool InitVisual(const wxGLAttributes& dispAttrs); + + // creates EGLSurface + bool CreateSurface(); + + virtual ~wxGLCanvasEGL(); + + + // implement wxGLCanvasBase methods + // -------------------------------- + + virtual bool SwapBuffers() wxOVERRIDE; + + + // 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 wxOVERRIDE; + + + // 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 NULL if EGLConfig couldn't be initialized, otherwise caller + // is responsible for freeing the pointer + static EGLConfig *InitConfig(const wxGLAttributes& dispAttrs); + + bool m_readyToDraw; + wl_compositor *m_wlCompositor; + wl_subcompositor *m_wlSubcompositor; + wl_callback *m_wlFrameCallbackHandler; + wl_egl_window *m_wlEGLWindow; + +private: + + EGLConfig *m_config; + EGLDisplay m_display; + EGLSurface m_surface; + + unsigned long m_xwindow; + wl_surface *m_wlSurface; + wl_region *m_wlRegion; + wl_subsurface *m_wlSubsurface; + + // the global/default versions of the above + static EGLConfig *ms_glEGLConfig; +}; + +// ---------------------------------------------------------------------------- +// 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) wxOVERRIDE + { + return wxGLCanvasEGL::InitDefaultConfig(attribList); + } + + // This method is not currently used by the library itself, but remains for + // backwards compatibility and also because wxGTK has it we could start + // using it for the same purpose in wxX11 too some day. + virtual void* GetXVisualInfo() wxOVERRIDE + { + return wxGLCanvasEGL::GetDefaultConfig(); + } + + // and override this wxApp method to clean up + virtual int OnExit() wxOVERRIDE + { + wxGLCanvasEGL::FreeDefaultConfig(); + + return wxGLAppBase::OnExit(); + } + +private: + wxDECLARE_DYNAMIC_CLASS(wxGLApp); +}; + +#endif // _WX_UNIX_GLEGL_H_ diff --git a/include/wx/utils.h b/include/wx/utils.h index 1ac67eeff8..c6d35299c2 100644 --- a/include/wx/utils.h +++ b/include/wx/utils.h @@ -780,6 +780,18 @@ void WXDLLIMPEXP_CORE wxGetMousePosition( int* x, int* y ); #ifdef __WXGTK__ WXDLLIMPEXP_CORE void *wxGetDisplay(); + enum wxDisplayType + { + wxDisplayNone, + wxDisplayX11, + wxDisplayWayland + }; + struct wxDisplayInfo + { + void* dpy; + wxDisplayType type; + }; + WXDLLIMPEXP_CORE wxDisplayInfo wxGetDisplayInfo(); #endif #ifdef __X__ diff --git a/setup.h.in b/setup.h.in index b724a18cbe..47fa4e5a02 100644 --- a/setup.h.in +++ b/setup.h.in @@ -549,6 +549,8 @@ #define wxUSE_GLCANVAS 0 +#define wxUSE_GLCANVAS_EGL 0 + #define wxUSE_RICHTEXT 0 diff --git a/src/gtk/glcanvas.cpp b/src/gtk/glcanvas.cpp index 67c7c50f73..4c63a82450 100644 --- a/src/gtk/glcanvas.cpp +++ b/src/gtk/glcanvas.cpp @@ -16,7 +16,12 @@ #include "wx/glcanvas.h" #include "wx/gtk/private/wrapgtk.h" +#ifdef GDK_WINDOWING_WAYLAND +#include +#endif +#ifdef GDK_WINDOWING_X11 #include +#endif #ifdef __WXGTK3__ extern "C" { @@ -43,6 +48,7 @@ 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,6 +76,7 @@ parent_set_hook(GSignalInvocationHint*, guint, const GValue* param_values, void* return true; } } +#endif //--------------------------------------------------------------------------- // wxGlCanvas @@ -160,15 +167,25 @@ wxGLCanvas::wxGLCanvas(wxWindow *parent, static bool IsAvailable() { -#ifdef GDK_WINDOWING_X11 - if ( !GDK_IS_X11_DISPLAY(gdk_display_get_default()) ) -#endif +#ifdef GDK_WINDOWING_WAYLAND + if ( GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default()) ) { - wxSafeShowMessage(_("Fatal Error"), _("wxGLCanvas is only supported on X11 currently. You may be able to\nwork around this by setting environment variable GDK_BACKEND=x11 before starting\nyour program.")); +#if wxUSE_GLCANVAS_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 // GDK_WINDOWING_WAYLAND - return true; +#ifdef GDK_WINDOWING_X11 + if ( GDK_IS_X11_DISPLAY(gdk_display_get_default()) ) + return true; +#endif + + wxSafeShowMessage(_("Fatal Error"), _("wxGLCanvas is only supported on Wayland and X11 currently. You may be able to\nwork around this by setting environment variable GDK_BACKEND=x11 before\nstarting your program.")); + return false; } bool wxGLCanvas::Create(wxWindow *parent, @@ -221,8 +238,10 @@ 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, NULL); +#endif wxWindow::Create( parent, id, pos, size, style, name ); #ifdef __WXGTK3__ @@ -251,6 +270,9 @@ void wxGLCanvas::GTKHandleRealized() #if WXWIN_COMPATIBILITY_2_8 GTKInitImplicitContext(); +#endif +#if wxUSE_GLCANVAS_EGL + CreateSurface(); #endif SendSizeEvent(); } diff --git a/src/gtk/utilsgtk.cpp b/src/gtk/utilsgtk.cpp index 4a7afc9edc..6dc15e1a2d 100644 --- a/src/gtk/utilsgtk.cpp +++ b/src/gtk/utilsgtk.cpp @@ -26,6 +26,9 @@ #include "wx/evtloop.h" #include "wx/gtk/private/wrapgtk.h" +#ifdef GDK_WINDOWING_WAYLAND +#include +#endif #ifdef GDK_WINDOWING_WIN32 #include #endif @@ -69,12 +72,31 @@ void wxBell() // display characteristics // ---------------------------------------------------------------------------- -#ifdef GDK_WINDOWING_X11 void *wxGetDisplay() { - return GDK_DISPLAY_XDISPLAY(gdk_window_get_display(wxGetTopLevelGDK())); + return wxGetDisplayInfo().dpy; } + +wxDisplayInfo wxGetDisplayInfo() +{ + wxDisplayInfo info = { NULL, wxDisplayNone }; + GdkDisplay *display = gdk_window_get_display(wxGetTopLevelGDK()); +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_DISPLAY(display)) { + info.dpy = GDK_DISPLAY_XDISPLAY(display); + info.type = wxDisplayX11; + return info; + } #endif +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY(display)) { + info.dpy = gdk_wayland_display_get_wl_display(display); + info.type = wxDisplayWayland; + return info; + } +#endif + return info; +} wxWindow* wxFindWindowAtPoint(const wxPoint& pt) { diff --git a/src/unix/glegl.cpp b/src/unix/glegl.cpp new file mode 100644 index 0000000000..e79ad23792 --- /dev/null +++ b/src/unix/glegl.cpp @@ -0,0 +1,654 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/unix/glegl.cpp +// Purpose: code common to all EGL-based wxGLCanvas implementations +// Author: Scott Talbert +// Created: 2017-12-26 +// Copyright: (c) 2017 Scott Talbert +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_GLCANVAS && wxUSE_GLCANVAS_EGL + +#ifndef WX_PRECOMP + #include "wx/log.h" +#endif //WX_PRECOMP + +#include "wx/glcanvas.h" + +#include +#ifdef GDK_WINDOWING_WAYLAND +#include +#include +#include +#endif +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include +#include + +// ---------------------------------------------------------------------------- +// wxGLContextAttrs: OpenGL rendering context attributes +// ---------------------------------------------------------------------------- +// EGL specific values + +wxGLContextAttrs& wxGLContextAttrs::CoreProfile() +{ + AddAttribBits(EGL_CONTEXT_OPENGL_PROFILE_MASK, + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::MajorVersion(int val) +{ + if ( val > 0 ) + { + AddAttribute(EGL_CONTEXT_MAJOR_VERSION); + AddAttribute(val); + } + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::MinorVersion(int val) +{ + if ( val >= 0 ) + { + AddAttribute(EGL_CONTEXT_MINOR_VERSION); + AddAttribute(val); + } + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile() +{ + AddAttribBits(EGL_CONTEXT_OPENGL_PROFILE_MASK, + EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ForwardCompatible() +{ + AddAttribute(EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE); + AddAttribute(EGL_TRUE); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ES2() +{ + AddAttribBits(EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::DebugCtx() +{ + AddAttribute(EGL_CONTEXT_OPENGL_DEBUG); + AddAttribute(EGL_TRUE); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::Robust() +{ + AddAttribute(EGL_CONTEXT_OPENGL_ROBUST_ACCESS); + AddAttribute(EGL_TRUE); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::NoResetNotify() +{ + AddAttribute(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY); + AddAttribute(EGL_NO_RESET_NOTIFICATION); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::LoseOnReset() +{ + AddAttribute(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY); + AddAttribute(EGL_LOSE_CONTEXT_ON_RESET); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ResetIsolation() +{ + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ReleaseFlush(int) +{ + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::PlatformDefaults() +{ + return *this; +} + +void wxGLContextAttrs::EndList() +{ + AddAttribute(EGL_NONE); +} + +// ---------------------------------------------------------------------------- +// wxGLAttributes: Visual/FBconfig attributes +// ---------------------------------------------------------------------------- + +wxGLAttributes& wxGLAttributes::RGBA() +{ + return *this; +} + +wxGLAttributes& wxGLAttributes::BufferSize(int val) +{ + if ( val >= 0 ) + { + AddAttribute(EGL_BUFFER_SIZE); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Level(int val) +{ + AddAttribute(EGL_LEVEL); + AddAttribute(val); + return *this; +} + +wxGLAttributes& wxGLAttributes::DoubleBuffer() +{ + return *this; +} + +wxGLAttributes& wxGLAttributes::Stereo() +{ + return *this; +} + +wxGLAttributes& wxGLAttributes::AuxBuffers(int) +{ + return *this; +} + +wxGLAttributes& wxGLAttributes::MinRGBA(int mRed, int mGreen, int mBlue, int mAlpha) +{ + if ( mRed >= 0) + { + AddAttribute(EGL_RED_SIZE); + AddAttribute(mRed); + } + if ( mGreen >= 0) + { + AddAttribute(EGL_GREEN_SIZE); + AddAttribute(mGreen); + } + if ( mBlue >= 0) + { + AddAttribute(EGL_BLUE_SIZE); + AddAttribute(mBlue); + } + if ( mAlpha >= 0) + { + AddAttribute(EGL_ALPHA_SIZE); + AddAttribute(mAlpha); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Depth(int val) +{ + if ( val >= 0 ) + { + AddAttribute(EGL_DEPTH_SIZE); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Stencil(int val) +{ + if ( val >= 0 ) + { + AddAttribute(EGL_STENCIL_SIZE); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::MinAcumRGBA(int, int, int, int) +{ + return *this; +} + +wxGLAttributes& wxGLAttributes::SampleBuffers(int val) +{ + if ( val >= 0 ) + { + AddAttribute(EGL_SAMPLE_BUFFERS); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Samplers(int val) +{ + if ( val >= 0 ) + { + AddAttribute(EGL_SAMPLES); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::FrameBuffersRGB() +{ + return *this; +} + +void wxGLAttributes::EndList() +{ + AddAttribute(EGL_NONE); +} + +wxGLAttributes& wxGLAttributes::PlatformDefaults() +{ + // No EGL specific values + return *this; +} + +wxGLAttributes& wxGLAttributes::Defaults() +{ + RGBA().DoubleBuffer().Depth(16).SampleBuffers(1).Samplers(4); + return *this; +} + +void wxGLAttributes::AddDefaultsForWXBefore31() +{ + // ParseAttribList() will add EndList(), don't do it now + DoubleBuffer(); +} + + +// ============================================================================ +// wxGLContext implementation +// ============================================================================ + +wxIMPLEMENT_CLASS(wxGLContext, wxObject); + +wxGLContext::wxGLContext(wxGLCanvas *win, + const wxGLContext *other, + const wxGLContextAttrs *ctxAttrs) + : m_glContext(NULL) +{ + const int* contextAttribs = NULL; + + if ( ctxAttrs ) + { + contextAttribs = ctxAttrs->GetGLAttrs(); + } + else if ( win->GetGLCTXAttrs().GetGLAttrs() ) + { + // If OpenGL context parameters were set at wxGLCanvas ctor, get them now + contextAttribs = win->GetGLCTXAttrs().GetGLAttrs(); + } + + m_isOk = false; + + EGLConfig *fbc = win->GetEGLConfig(); + wxCHECK_RET( fbc, "Invalid EGLConfig for OpenGL" ); + + m_glContext = eglCreateContext(wxGLCanvasEGL::GetDisplay(), fbc[0], + other ? other->m_glContext : EGL_NO_CONTEXT, + contextAttribs); + + if ( !m_glContext ) + wxLogMessage(_("Couldn't create OpenGL context")); + else + m_isOk = true; +} + +wxGLContext::~wxGLContext() +{ + if ( !m_glContext ) + return; + + if ( m_glContext == eglGetCurrentContext() ) + eglMakeCurrent(wxGLCanvasEGL::GetDisplay(), EGL_NO_SURFACE, + EGL_NO_SURFACE, EGL_NO_CONTEXT); + + eglDestroyContext(wxGLCanvasEGL::GetDisplay(), m_glContext); +} + +bool wxGLContext::SetCurrent(const wxGLCanvas& win) const +{ + if ( !m_glContext ) + return false; + + return eglMakeCurrent(win.GetEGLDisplay(), win.GetEGLSurface(), + win.GetEGLSurface(), m_glContext); +} + +// ============================================================================ +// wxGLCanvasEGL implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// initialization methods and dtor +// ---------------------------------------------------------------------------- + +wxGLCanvasEGL::wxGLCanvasEGL() +{ + m_config = NULL; + m_display = NULL; + m_surface = EGL_NO_SURFACE; + m_wlCompositor = NULL; + m_wlSubcompositor = NULL; + m_wlFrameCallbackHandler = NULL; + m_wlEGLWindow = NULL; + m_wlSurface = NULL; + m_wlRegion = NULL; + m_wlSubsurface = NULL; + m_readyToDraw = false; +} + +bool wxGLCanvasEGL::InitVisual(const wxGLAttributes& dispAttrs) +{ + m_config = InitConfig(dispAttrs); + if ( !m_config ) + { + wxFAIL_MSG("Failed to get an EGLConfig for the requested attributes."); + } + return m_config != NULL; +} + +/* static */ +EGLDisplay wxGLCanvasEGL::GetDisplay() +{ + wxDisplayInfo info = wxGetDisplayInfo(); + EGLenum platform; + switch ( info.type ) + { + case wxDisplayX11: + platform = EGL_PLATFORM_X11_EXT; + break; + case wxDisplayWayland: + platform = EGL_PLATFORM_WAYLAND_EXT; + break; + default: + return EGL_NO_DISPLAY; + } + + return eglGetPlatformDisplay(platform, info.dpy, NULL); +} + +extern "C" +{ + +static void wl_global (void *data, + struct wl_registry *wl_registry, + uint32_t name, + const char *interface, + uint32_t) +{ + wxGLCanvasEGL *glc = static_cast(data); + + if ( !strcmp (interface, "wl_compositor") ) + glc->m_wlCompositor = (struct wl_compositor *) wl_registry_bind (wl_registry, name, &wl_compositor_interface, 3); + else if ( !strcmp (interface, "wl_subcompositor") ) + glc->m_wlSubcompositor = (struct wl_subcompositor *) wl_registry_bind (wl_registry, name, &wl_subcompositor_interface, 1); +} + +static void wl_global_remove (void *, + struct wl_registry *, + uint32_t) +{ +} + +static const struct wl_registry_listener wl_registry_listener = { + wl_global, + wl_global_remove +}; + +static void wl_frame_callback_handler(void* data, + struct wl_callback *, + uint32_t) +{ + wxGLCanvasEGL *glc = static_cast(data); + glc->m_readyToDraw = true; + g_clear_pointer(&glc->m_wlFrameCallbackHandler, wl_callback_destroy); + glc->SendSizeEvent(); + gtk_widget_queue_draw(glc->m_wxwindow); +} + +static const struct wl_callback_listener wl_frame_listener = { + wl_frame_callback_handler +}; + +static void gtk_glcanvas_size_callback(GtkWidget *widget, + GtkAllocation *, + 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); +} + +} // extern "C" + +bool wxGLCanvasEGL::CreateSurface() +{ + m_display = GetDisplay(); + if ( m_display == EGL_NO_DISPLAY ) + { + wxFAIL_MSG("Unable to get EGL Display"); + return false; + } + + GdkWindow *window = GTKGetDrawingWindow(); +#ifdef GDK_WINDOWING_X11 + if ( GDK_IS_X11_WINDOW(window) ) + { + m_xwindow = GDK_WINDOW_XID(window); + m_surface = eglCreatePlatformWindowSurface(m_display, *m_config, + &m_xwindow, NULL); + m_readyToDraw = true; + } +#endif +#ifdef GDK_WINDOWING_WAYLAND + if ( GDK_IS_WAYLAND_WINDOW(window) ) + { + int x, y; + gdk_window_get_origin(window, &x, &y); + int w = gdk_window_get_width(window); + int h = gdk_window_get_height(window); + struct wl_display *display = gdk_wayland_display_get_wl_display(gdk_window_get_display(window)); + struct wl_surface *surface = gdk_wayland_window_get_wl_surface(window); + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, &wl_registry_listener, this); + wl_display_roundtrip(display); + if ( !m_wlCompositor || !m_wlSubcompositor ) + { + wxFAIL_MSG("Invalid Wayland compositor or subcompositor"); + return false; + } + m_wlSurface = wl_compositor_create_surface(m_wlCompositor); + m_wlRegion = wl_compositor_create_region(m_wlCompositor); + m_wlSubsurface = wl_subcompositor_get_subsurface(m_wlSubcompositor, + m_wlSurface, + surface); + wl_surface_set_input_region(m_wlSurface, m_wlRegion); + wl_subsurface_set_desync(m_wlSubsurface); + wl_subsurface_set_position(m_wlSubsurface, x, y); + int scale = gdk_window_get_scale_factor(window); + wl_surface_set_buffer_scale(m_wlSurface, scale); + m_wlEGLWindow = wl_egl_window_create(m_wlSurface, w * scale, + h * scale); + m_surface = eglCreatePlatformWindowSurface(m_display, *m_config, + m_wlEGLWindow, NULL); + m_wlFrameCallbackHandler = wl_surface_frame(surface); + wl_callback_add_listener(m_wlFrameCallbackHandler, + &wl_frame_listener, this); + g_signal_connect(m_widget, "size-allocate", + G_CALLBACK(gtk_glcanvas_size_callback), this); + } +#endif + + if ( m_surface == EGL_NO_SURFACE ) + { + wxFAIL_MSG("Unable to create EGL surface"); + return false; + } + + return true; +} + +wxGLCanvasEGL::~wxGLCanvasEGL() +{ + if ( m_config && m_config != ms_glEGLConfig ) + delete m_config; + if ( m_surface ) + eglDestroySurface(m_display, m_surface); + g_clear_pointer(&m_wlEGLWindow, wl_egl_window_destroy); + g_clear_pointer(&m_wlSubsurface, wl_subsurface_destroy); + g_clear_pointer(&m_wlSurface, wl_surface_destroy); + g_clear_pointer(&m_wlFrameCallbackHandler, wl_callback_destroy); +} + +// ---------------------------------------------------------------------------- +// working with GL attributes +// ---------------------------------------------------------------------------- + +/* static */ +bool wxGLCanvasBase::IsExtensionSupported(const char *extension) +{ + EGLDisplay dpy = eglGetDisplay(static_cast(wxGetDisplay())); + + return IsExtensionInList(eglQueryString(dpy, EGL_EXTENSIONS), extension); +} + + +/* static */ +EGLConfig *wxGLCanvasEGL::InitConfig(const wxGLAttributes& dispAttrs) +{ + const int* attrsList = dispAttrs.GetGLAttrs(); + if ( !attrsList ) + { + wxFAIL_MSG("wxGLAttributes object is empty."); + return NULL; + } + + EGLDisplay dpy = GetDisplay(); + if ( dpy == EGL_NO_DISPLAY ) { + wxFAIL_MSG("Unable to get EGL Display"); + return NULL; + } + if ( !eglInitialize(dpy, NULL, NULL) ) + { + wxFAIL_MSG("eglInitialize failed"); + return NULL; + } + if ( !eglBindAPI(EGL_OPENGL_API) ) { + wxFAIL_MSG("eglBindAPI failed"); + return NULL; + } + + EGLConfig *config = new EGLConfig; + int returned; + // Use the first good match + if ( eglChooseConfig(dpy, attrsList, config, 1, &returned) && returned == 1 ) + { + return config; + } + else + { + wxFAIL_MSG("eglChooseConfig failed"); + delete config; + return NULL; + } +} + +/* static */ +bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs) +{ + wxScopedPtr config(wxGLCanvasEGL::InitConfig(dispAttrs)); + return config != NULL; +} + +/* static */ +bool wxGLCanvasBase::IsDisplaySupported(const int *attribList) +{ + wxGLAttributes dispAttrs; + ParseAttribList(attribList, dispAttrs); + + return IsDisplaySupported(dispAttrs); +} + +// ---------------------------------------------------------------------------- +// default visual management +// ---------------------------------------------------------------------------- + +EGLConfig *wxGLCanvasEGL::ms_glEGLConfig = NULL; + +/* static */ +bool wxGLCanvasEGL::InitDefaultConfig(const int *attribList) +{ + FreeDefaultConfig(); + wxGLAttributes dispAttrs; + ParseAttribList(attribList, dispAttrs); + + ms_glEGLConfig = InitConfig(dispAttrs); + return ms_glEGLConfig != NULL; +} + +/* static */ +void wxGLCanvasEGL::FreeDefaultConfig() +{ + if ( ms_glEGLConfig ) + { + delete ms_glEGLConfig; + ms_glEGLConfig = NULL; + } +} + +// ---------------------------------------------------------------------------- +// other GL methods +// ---------------------------------------------------------------------------- + +bool wxGLCanvasEGL::SwapBuffers() +{ + // Under Wayland, if eglSwapBuffers() is called before the wl_surface has + // been realized, it will deadlock. Thus, we need to avoid swapping before + // this has happened. + if ( !m_readyToDraw ) + return false; + + return eglSwapBuffers(m_display, m_surface); +} + +bool wxGLCanvasEGL::IsShownOnScreen() const +{ + wxDisplayInfo info = wxGetDisplayInfo(); + switch ( info.type ) + { + case wxDisplayX11: + return GetXWindow() && wxGLCanvasBase::IsShownOnScreen(); + case wxDisplayWayland: + return m_readyToDraw && wxGLCanvasBase::IsShownOnScreen(); + default: + return false; + } +} + +#endif // wxUSE_GLCANVAS && wxUSE_GLCANVAS_EGL + diff --git a/src/unix/glx11.cpp b/src/unix/glx11.cpp index e3f87feef8..b970db5762 100644 --- a/src/unix/glx11.cpp +++ b/src/unix/glx11.cpp @@ -18,7 +18,7 @@ // for compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" -#if wxUSE_GLCANVAS +#if wxUSE_GLCANVAS && !wxUSE_GLCANVAS_EGL #ifndef WX_PRECOMP #include "wx/log.h"