diff options
-rw-r--r-- | build/win32/Makefile.am | 1 | ||||
-rw-r--r-- | build/win32/README_EGL_MSVC.txt | 29 | ||||
-rw-r--r-- | configure.ac | 37 | ||||
-rw-r--r-- | gdk/gdkgl.c | 13 | ||||
-rw-r--r-- | gdk/gdkglcontext.c | 10 | ||||
-rw-r--r-- | gdk/win32/Makefile.am | 4 | ||||
-rw-r--r-- | gdk/win32/gdkdisplay-win32.c | 12 | ||||
-rw-r--r-- | gdk/win32/gdkdisplay-win32.h | 18 | ||||
-rw-r--r-- | gdk/win32/gdkglcontext-win32.c | 673 | ||||
-rw-r--r-- | gdk/win32/gdkglcontext-win32.h | 10 | ||||
-rw-r--r-- | gdk/win32/gdkwindow-win32.c | 49 | ||||
-rw-r--r-- | gdk/win32/gdkwindow-win32.h | 15 |
12 files changed, 728 insertions, 143 deletions
diff --git a/build/win32/Makefile.am b/build/win32/Makefile.am index 39fed6fe69..e47c8c411e 100644 --- a/build/win32/Makefile.am +++ b/build/win32/Makefile.am @@ -42,6 +42,7 @@ EXTRA_DIST += \ replace.py \ pc_base.py \ gtkpc.py \ + README_EGL_MSVC.txt \ $(GENERATED_ITEMS) -include $(top_srcdir)/git.mk diff --git a/build/win32/README_EGL_MSVC.txt b/build/win32/README_EGL_MSVC.txt new file mode 100644 index 0000000000..f32b9a62fd --- /dev/null +++ b/build/win32/README_EGL_MSVC.txt @@ -0,0 +1,29 @@ +Notes on enabling EGL (ANGLE/D3D support) for Windows/Visual Studio builds
+==========================================================================
+There is now support in the GL context creation code for Windows in GDK for
+creating and using EGL (OpenGL ES 3) contexts, which can be used instead of
+the existing OpenGL (Desktop) support, especially when the graphics drivers
+do not support OpenGL adequately.
+
+This support is not enabled by default in the project files. In order to do
+so, please do the following:
+
+-Obtain or compile a build of recent version of ANGLE. The one that comes
+ with QT 5.10.x is sufficiently recent, but not the one that comes with QT-
+ 5.6.x. Note that Visual Studio 2013 or later is required for building
+ ANGLE from QT-5.10.x, but the Visual Studio 2013-built ANGLE DLLs does work
+ without problems with GTK+ built with Visual Studio 2008~2013. You may
+ need to obtain D3Dcompiler_[47|43|42].dll if it does not come with the
+ system (which is part of the DirectX runtimes). Its headers and .lib
+ needs to be set to be found by the compiler and linker respectively before
+ building libepoxy.
+-Build libepoxy with EGL support, which has to be enabled explicitly on
+ Windows builds. Pass in -Degl=yes when building libepoxy using Meson.
+ Build and install, making sure the headers and .lib can be located by the
+ compiler and linker respectively.
+-Open the vsX/gtk+.sln, and open the project properties in the "gdk3-win32"
+ project. Under "C/C++", add GDK_WIN32_ENABLE_EGL in the "Preprocessor
+ Definitions" to the existing definitions in there for the configuration
+ that is being built. Then build the solution.
+-To force the use of the EGL code, set the envvar GDK_GL=(...,)gles , where (...,)
+ are the other GDK_GL options desired.
diff --git a/configure.ac b/configure.ac index 05843eda14..f07279db87 100644 --- a/configure.ac +++ b/configure.ac @@ -1434,6 +1434,43 @@ else X11_PREFIX="$ac_default_prefix" fi +AC_ARG_ENABLE(win32-gles, + [AS_HELP_STRING([--enable-win32-gles], + [enable OpenGL ES rendering in Win32 backend, disabled by default])], + [win32_gles=yes], + [win32_gles=no]) + +if test x"$enable_win32_backend" = xyes; then + AC_MSG_CHECKING(WGL support in epoxy) + WGL_SUPPORT="`$PKG_CONFIG --variable=epoxy_has_wgl epoxy`" + if test x"$WGL_SUPPORT" = x1; then + AC_MSG_RESULT([supported]) + else + AC_MSG_ERROR([ +*** epoxy was not built with WGL support or epoxy version is too old. +*** WGL support in epoxy is enabled by default for all Windows builds, +*** and is used by GTK+ uncondititonally. If it is not there, then +*** something is very wrong. +]) + fi + if test x"$win32_gles" = xyes; then + AC_MSG_CHECKING(EGL support in epoxy) + EGL_SUPPORT="`$PKG_CONFIG --variable=epoxy_has_egl epoxy`" + if test x"$EGL_SUPPORT" = x1; then + AC_MSG_RESULT([supported]) + else + AC_MSG_ERROR([ +*** epoxy was not built with EGL support or epoxy version is too old. +*** EGL support in epoxy is disabled by default in Windows builds, +*** you might need to rebuild epoxy with explicit --enable-egl=yes. +*** EGL support is needed for OpenGL ES rendering. +]) + fi + fi +fi + +AM_CONDITIONAL(WIN32_GLES, test x"$platform_win32" = xyes -a x"$win32_gles" = xyes) + GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`" ATK_PREFIX="`$PKG_CONFIG --variable=prefix atk`" PANGO_PREFIX="`$PKG_CONFIG --variable=prefix pango`" diff --git a/gdk/gdkgl.c b/gdk/gdkgl.c index 8e7b8c2310..933e204439 100644 --- a/gdk/gdkgl.c +++ b/gdk/gdkgl.c @@ -22,6 +22,10 @@ #include "gdkinternals.h" +#ifdef GDK_WINDOWING_WIN32 +# include "win32/gdkwin32.h" +#endif + #include <epoxy/gl.h> #include <math.h> #include <string.h> @@ -641,6 +645,13 @@ gdk_cairo_draw_from_gl (cairo_t *cr, { /* Software fallback */ int major, minor, version; + gboolean es_read_bgra = FALSE; + +#ifdef GDK_WINDOWING_WIN32 + /* on ANGLE GLES, we need to set the glReadPixel() format as GL_BGRA instead */ + if (GDK_WIN32_IS_GL_CONTEXT(paint_context)) + es_read_bgra = TRUE; +#endif gdk_gl_context_get_version (paint_context, &major, &minor); version = major * 100 + minor; @@ -683,7 +694,7 @@ gdk_cairo_draw_from_gl (cairo_t *cr, glReadPixels (x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, cairo_image_surface_get_data (image)); else - glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, + glReadPixels (x, y, width, height, es_read_bgra ? GL_BGRA : GL_RGBA, GL_UNSIGNED_BYTE, cairo_image_surface_get_data (image)); glPixelStorei (GL_PACK_ROW_LENGTH, 0); diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index df538b0c77..dfbed63ca5 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -793,11 +793,17 @@ gdk_gl_context_check_extensions (GdkGLContext *context) has_npot = priv->gl_version >= 20; has_texture_rectangle = FALSE; - /* This should check for GL_NV_framebuffer_blit - see extension at: + /* This should check for GL_NV_framebuffer_blit as well - see extension at: * * https://www.khronos.org/registry/gles/extensions/NV/NV_framebuffer_blit.txt + * + * for ANGLE, we can enable bit blitting if we have the + * GL_ANGLE_framebuffer_blit extension */ - priv->has_gl_framebuffer_blit = FALSE; + if (epoxy_has_gl_extension ("GL_ANGLE_framebuffer_blit")) + priv->has_gl_framebuffer_blit = TRUE; + else + priv->has_gl_framebuffer_blit = FALSE; /* No OES version */ priv->has_frame_terminator = FALSE; diff --git a/gdk/win32/Makefile.am b/gdk/win32/Makefile.am index 7c37427f07..0504428580 100644 --- a/gdk/win32/Makefile.am +++ b/gdk/win32/Makefile.am @@ -17,6 +17,10 @@ AM_CPPFLAGS = \ $(GDK_WIN32_EXTRA_CFLAGS) \ -DGDK_COMPILATION +if WIN32_GLES +AM_CPPFLAGS += "-DGDK_WIN32_ENABLE_EGL=1" +endif #WIN32_GLES + LDADDS = $(GDK_DEP_LIBS) noinst_LTLIBRARIES = libgdk-win32.la diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c index de3fab2bef..4f095019b7 100644 --- a/gdk/win32/gdkdisplay-win32.c +++ b/gdk/win32/gdkdisplay-win32.c @@ -31,6 +31,10 @@ #include "gdkmonitor-win32.h" #include "gdkwin32.h" +#ifdef GDK_WIN32_ENABLE_EGL +# include <epoxy/egl.h> +#endif + static int debug_indent = 0; static GdkMonitor * @@ -825,6 +829,14 @@ gdk_win32_display_dispose (GObject *object) _gdk_screen_close (display_win32->screen); +#ifdef GDK_WIN32_ENABLE_EGL + if (display_win32->egl_disp != EGL_NO_DISPLAY) + { + eglTerminate (display_win32->egl_disp); + display_win32->egl_disp = EGL_NO_DISPLAY; + } +#endif + if (display_win32->hwnd != NULL) { DestroyWindow (display_win32->hwnd); diff --git a/gdk/win32/gdkdisplay-win32.h b/gdk/win32/gdkdisplay-win32.h index 99981af5ee..ad8db96f0f 100644 --- a/gdk/win32/gdkdisplay-win32.h +++ b/gdk/win32/gdkdisplay-win32.h @@ -19,6 +19,10 @@ #include "gdkdisplayprivate.h" +#ifdef GDK_WIN32_ENABLE_EGL +# include <epoxy/egl.h> +#endif + #ifndef __GDK_DISPLAY__WIN32_H__ #define __GDK_DISPLAY__WIN32_H__ @@ -75,6 +79,14 @@ struct _GdkWin32Display guint gl_version; HWND gl_hwnd; +#ifdef GDK_WIN32_ENABLE_EGL + /* EGL (Angle) Items */ + guint have_egl : 1; + guint egl_version; + EGLDisplay egl_disp; + HDC hdc_egl_temp; +#endif + GPtrArray *monitors; guint hasWglARBCreateContext : 1; @@ -83,6 +95,12 @@ struct _GdkWin32Display guint hasWglARBPixelFormat : 1; guint hasWglARBmultisample : 1; +#ifdef GDK_WIN32_ENABLE_EGL + guint hasEglKHRCreateContext : 1; + guint hasEglSurfacelessContext : 1; + EGLint egl_min_swap_interval; +#endif + /* HiDPI Items */ guint have_at_least_win81 : 1; GdkWin32ProcessDpiAwareness dpi_aware_type; diff --git a/gdk/win32/gdkglcontext-win32.c b/gdk/win32/gdkglcontext-win32.c index 593a991f31..7a6ff8ee5a 100644 --- a/gdk/win32/gdkglcontext-win32.c +++ b/gdk/win32/gdkglcontext-win32.c @@ -41,6 +41,10 @@ #include <cairo.h> #include <epoxy/wgl.h> +#ifdef GDK_WIN32_ENABLE_EGL +# include <epoxy/egl.h> +#endif + G_DEFINE_TYPE (GdkWin32GLContext, gdk_win32_gl_context, GDK_TYPE_GL_CONTEXT) static void @@ -50,6 +54,7 @@ _gdk_win32_gl_context_dispose (GObject *gobject) GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (gobject); GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)); GdkWindow *window = gdk_gl_context_get_window (context); + GdkWindowImplWin32 *impl = NULL; if (context_win32->hglrc != NULL) { @@ -64,9 +69,28 @@ _gdk_win32_gl_context_dispose (GObject *gobject) ReleaseDC (display_win32->gl_hwnd, context_win32->gl_hdc); } +#ifdef GDK_WIN32_ENABLE_EGL + if (context_win32->egl_context != EGL_NO_CONTEXT) + { + if (eglGetCurrentContext () == context_win32->egl_context) + eglMakeCurrent(display_win32->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + + GDK_NOTE (OPENGL, g_message ("Destroying EGL (ANGLE) context")); + + eglDestroyContext (display_win32->egl_disp, + context_win32->egl_context); + context_win32->egl_context = EGL_NO_CONTEXT; + + impl = GDK_WINDOW_IMPL_WIN32 (window->impl); + + ReleaseDC (display_win32->gl_hwnd, context_win32->gl_hdc); + } +#endif + if (window != NULL && window->impl != NULL) { - GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl); + impl = GDK_WINDOW_IMPL_WIN32 (window->impl); if (impl->suppress_layered > 0) impl->suppress_layered--; @@ -126,11 +150,12 @@ _gdk_win32_gl_context_end_frame (GdkGLContext *context, GdkWindow *window = gdk_gl_context_get_window (context); GdkWin32Display *display = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context))); - gboolean can_wait = display->hasWglOMLSyncControl; gdk_gl_context_make_current (context); - if (context_win32->do_frame_sync) + if (!gdk_gl_context_get_use_es (context)) { + gboolean can_wait = display->hasWglOMLSyncControl; + if (context_win32->do_frame_sync) { glFinish (); @@ -147,21 +172,30 @@ _gdk_win32_gl_context_end_frame (GdkGLContext *context, &ust, &msc, &sbc); } } + + /* EGL does not have do_blit_swap */ + if (context_win32->do_blit_swap) + { + glDrawBuffer(GL_FRONT); + glReadBuffer(GL_BACK); + gdk_gl_blit_region (window, painted); + glDrawBuffer(GL_BACK); + glFlush(); + + if (gdk_gl_context_has_frame_terminator (context)) + glFrameTerminatorGREMEDY (); + } + else + SwapBuffers (context_win32->gl_hdc); } - if (context_win32->do_blit_swap) +#ifdef GDK_WIN32_ENABLE_EGL + else { - glDrawBuffer(GL_FRONT); - glReadBuffer(GL_BACK); - gdk_gl_blit_region (window, painted); - glDrawBuffer(GL_BACK); - glFlush(); - - if (gdk_gl_context_has_frame_terminator (context)) - glFrameTerminatorGREMEDY (); + EGLSurface egl_surface = _gdk_win32_window_get_egl_surface (window, context_win32->egl_config, FALSE); + eglSwapBuffers (display->egl_disp, egl_surface); } - else - SwapBuffers (context_win32->gl_hdc); +#endif } void @@ -180,6 +214,7 @@ _gdk_win32_window_invalidate_for_new_frame (GdkWindow *window, context_win32 = GDK_WIN32_GL_CONTEXT (window->gl_paint_context); context_win32->do_blit_swap = FALSE; + /* gdk_gl_context_has_framebuffer_blit() is for Desktop GL only ! */ if (gdk_gl_context_has_framebuffer_blit (window->gl_paint_context) && cairo_region_contains_rectangle (update_area, &whole_window) != CAIRO_REGION_OVERLAP_IN) { @@ -453,64 +488,152 @@ _gdk_init_dummy_context (GdkWGLDummy *dummy, return best_idx; } +#ifdef GDK_WIN32_ENABLE_EGL + +#ifndef EGL_PLATFORM_ANGLE_ANGLE +#define EGL_PLATFORM_ANGLE_ANGLE 0x3202 +#endif + +#ifndef EGL_PLATFORM_ANGLE_TYPE_ANGLE +#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 +#endif + +#ifndef EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE +#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 +#endif + +static EGLDisplay +_gdk_win32_get_egl_display (GdkWin32Display *display) +{ + EGLDisplay disp; + gboolean success = FALSE; + + if (epoxy_has_egl_extension (NULL, "EGL_EXT_platform_base")) + { + PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay = (void *) eglGetProcAddress ("eglGetPlatformDisplayEXT"); + if (getPlatformDisplay) + { + EGLint disp_attr[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE}; + + disp = getPlatformDisplay (EGL_PLATFORM_ANGLE_ANGLE, display->hdc_egl_temp, disp_attr); + + if (disp != EGL_NO_DISPLAY) + return disp; + } + } + return eglGetDisplay (display->hdc_egl_temp); +} +#endif + static gboolean _gdk_win32_display_init_gl (GdkDisplay *display, const gboolean need_alpha_bits) { GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display); gint best_idx = 0; - GdkWGLDummy dummy; - - if (display_win32->have_wgl) + gboolean disable_wgl = FALSE; + +#ifdef GDK_WIN32_ENABLE_EGL + EGLDisplay egl_disp; + disable_wgl = (_gdk_gl_flags & GDK_GL_GLES) != 0; +#endif + + if (display_win32->have_wgl +#ifdef GDK_WIN32_ENABLE_EGL + || display_win32->have_egl +#endif + ) return TRUE; - memset (&dummy, 0, sizeof (GdkWGLDummy)); + if (!disable_wgl) + { + /* acquire and cache dummy Window (HWND & HDC) and + * dummy GL Context, it is used to query functions + * and used for other stuff as well + */ + GdkWGLDummy dummy; + memset (&dummy, 0, sizeof (GdkWGLDummy)); + + best_idx = _gdk_init_dummy_context (&dummy, need_alpha_bits); - /* acquire and cache dummy Window (HWND & HDC) and - * dummy GL Context, it is used to query functions - * and used for other stuff as well - */ - best_idx = _gdk_init_dummy_context (&dummy, need_alpha_bits); + if (best_idx == 0 || !wglMakeCurrent (dummy.hdc, dummy.hglrc)) + return FALSE; - if (best_idx == 0 || !wglMakeCurrent (dummy.hdc, dummy.hglrc)) - return FALSE; + display_win32->have_wgl = TRUE; + display_win32->gl_version = epoxy_gl_version (); + + display_win32->hasWglARBCreateContext = + epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_create_context"); + display_win32->hasWglEXTSwapControl = + epoxy_has_wgl_extension (dummy.hdc, "WGL_EXT_swap_control"); + display_win32->hasWglOMLSyncControl = + epoxy_has_wgl_extension (dummy.hdc, "WGL_OML_sync_control"); + display_win32->hasWglARBPixelFormat = + epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_pixel_format"); + display_win32->hasWglARBmultisample = + epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_multisample"); + + GDK_NOTE (OPENGL, + g_print ("WGL API version %d.%d found\n" + " - Vendor: %s\n" + " - Checked extensions:\n" + "\t* WGL_ARB_pixel_format: %s\n" + "\t* WGL_ARB_create_context: %s\n" + "\t* WGL_EXT_swap_control: %s\n" + "\t* WGL_OML_sync_control: %s\n" + "\t* WGL_ARB_multisample: %s\n", + display_win32->gl_version / 10, + display_win32->gl_version % 10, + glGetString (GL_VENDOR), + display_win32->hasWglARBPixelFormat ? "yes" : "no", + display_win32->hasWglARBCreateContext ? "yes" : "no", + display_win32->hasWglEXTSwapControl ? "yes" : "no", + display_win32->hasWglOMLSyncControl ? "yes" : "no", + display_win32->hasWglARBmultisample ? "yes" : "no")); + + wglMakeCurrent (NULL, NULL); - display_win32->have_wgl = TRUE; - display_win32->gl_version = epoxy_gl_version (); + _destroy_dummy_gl_context (dummy); + return TRUE; + } + +#ifdef GDK_WIN32_ENABLE_EGL + egl_disp = _gdk_win32_get_egl_display (display_win32); + + if (egl_disp == EGL_NO_DISPLAY || + !eglInitialize (egl_disp, NULL, NULL)) + { + if (egl_disp != EGL_NO_DISPLAY) + { + eglTerminate (egl_disp); + egl_disp = EGL_NO_DISPLAY; + } + + return FALSE; + } + + display_win32->egl_disp = egl_disp; + display_win32->have_egl = TRUE; + display_win32->egl_version = epoxy_egl_version (egl_disp); + + eglBindAPI(EGL_OPENGL_ES_API); + + display_win32->hasEglSurfacelessContext = + epoxy_has_egl_extension (egl_disp, "EGL_KHR_surfaceless_context"); - display_win32->hasWglARBCreateContext = - epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_create_context"); - display_win32->hasWglEXTSwapControl = - epoxy_has_wgl_extension (dummy.hdc, "WGL_EXT_swap_control"); - display_win32->hasWglOMLSyncControl = - epoxy_has_wgl_extension (dummy.hdc, "WGL_OML_sync_control"); - display_win32->hasWglARBPixelFormat = - epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_pixel_format"); - display_win32->hasWglARBmultisample = - epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_multisample"); GDK_NOTE (OPENGL, - g_print ("WGL API version %d.%d found\n" + g_print ("EGL API version %d.%d found\n" " - Vendor: %s\n" " - Checked extensions:\n" - "\t* WGL_ARB_pixel_format: %s\n" - "\t* WGL_ARB_create_context: %s\n" - "\t* WGL_EXT_swap_control: %s\n" - "\t* WGL_OML_sync_control: %s\n" - "\t* WGL_ARB_multisample: %s\n", - display_win32->gl_version / 10, - display_win32->gl_version % 10, - glGetString (GL_VENDOR), - display_win32->hasWglARBPixelFormat ? "yes" : "no", - display_win32->hasWglARBCreateContext ? "yes" : "no", - display_win32->hasWglEXTSwapControl ? "yes" : "no", - display_win32->hasWglOMLSyncControl ? "yes" : "no", - display_win32->hasWglARBmultisample ? "yes" : "no")); - - wglMakeCurrent (NULL, NULL); - _destroy_dummy_gl_context (dummy); + "\t* EGL_KHR_surfaceless_context: %s\n", + display_win32->egl_version / 10, + display_win32->egl_version % 10, + eglQueryString (display_win32->egl_disp, EGL_VENDOR), + display_win32->hasEglSurfacelessContext ? "yes" : "no")); return TRUE; +#endif } /* Setup the legacy context after creating it */ @@ -688,6 +811,132 @@ _set_pixformat_for_hdc (HDC hdc, return TRUE; } +#ifdef GDK_WIN32_ENABLE_EGL + +#define MAX_EGL_ATTRS 30 + +static gboolean +find_eglconfig_for_window (GdkWin32Display *display, + EGLConfig *egl_config_out, + EGLint *min_swap_interval_out, + gboolean need_alpha_bits, + GError **error) +{ + EGLint attrs[MAX_EGL_ATTRS]; + EGLint count; + EGLConfig *configs, chosen_config; + + int i = 0; + + EGLDisplay egl_disp = display->egl_disp; + + attrs[i++] = EGL_CONFORMANT; + attrs[i++] = EGL_OPENGL_ES2_BIT; + attrs[i++] = EGL_SURFACE_TYPE; + attrs[i++] = EGL_WINDOW_BIT; + + attrs[i++] = EGL_COLOR_BUFFER_TYPE; + attrs[i++] = EGL_RGB_BUFFER; + + attrs[i++] = EGL_RED_SIZE; + attrs[i++] = 1; + attrs[i++] = EGL_GREEN_SIZE; + attrs[i++] = 1; + attrs[i++] = EGL_BLUE_SIZE; + attrs[i++] = 1; + + if (need_alpha_bits) + { + attrs[i++] = EGL_ALPHA_SIZE; + attrs[i++] = 1; + } + else + { + attrs[i++] = EGL_ALPHA_SIZE; + attrs[i++] = EGL_DONT_CARE; + } + + attrs[i++] = EGL_NONE; + g_assert (i < MAX_EGL_ATTRS); + + if (!eglChooseConfig (display->egl_disp, attrs, NULL, 0, &count) || count < 1) + { + g_set_error_literal (error, GDK_GL_ERROR, + GDK_GL_ERROR_UNSUPPORTED_FORMAT, + _("No available configurations for the given pixel format")); + return FALSE; + } + + configs = g_new (EGLConfig, count); + + if (!eglChooseConfig (display->egl_disp, attrs, configs, count, &count) || count < 1) + { + g_set_error_literal (error, GDK_GL_ERROR, + GDK_GL_ERROR_UNSUPPORTED_FORMAT, + _("No available configurations for the given pixel format")); + return FALSE; + } + + /* Pick first valid configuration i guess? */ + chosen_config = configs[0]; + + if (!eglGetConfigAttrib (display->egl_disp, chosen_config, + EGL_MIN_SWAP_INTERVAL, min_swap_interval_out)) + { + g_set_error_literal (error, GDK_GL_ERROR, + GDK_GL_ERROR_NOT_AVAILABLE, + "Could not retrieve the minimum swap interval"); + g_free (configs); + return FALSE; + } + + if (egl_config_out != NULL) + *egl_config_out = chosen_config; + + g_free (configs); + + return TRUE; +} + +#define N_EGL_ATTRS 16 + +static EGLContext +_create_egl_context (EGLDisplay display, + EGLConfig config, + GdkGLContext *share, + int flags, + int major, + int minor, + gboolean *is_legacy) +{ + EGLContext ctx; + EGLint context_attribs[N_EGL_ATTRS]; + int i = 0; + + /* ANGLE does not support the GL_OES_vertex_array_object extension, so we need to use ES3 directly */ + context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION; + context_attribs[i++] = 3; + + /* Specify the flags */ + context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR; + context_attribs[i++] = flags; + + context_attribs[i++] = EGL_NONE; + g_assert (i < N_EGL_ATTRS); + + ctx = eglCreateContext (display, + config, + share != NULL ? GDK_WIN32_GL_CONTEXT (share)->egl_context + : EGL_NO_CONTEXT, + context_attribs); + + if (ctx != EGL_NO_CONTEXT) + GDK_NOTE (OPENGL, g_message ("Created EGL context[%p]", ctx)); + + return ctx; +} +#endif /* GDK_WIN32_ENABLE_EGL */ + gboolean _gdk_win32_gl_context_realize (GdkGLContext *context, GError **error) @@ -695,83 +944,143 @@ _gdk_win32_gl_context_realize (GdkGLContext *context, GdkGLContext *share = gdk_gl_context_get_shared_context (context); GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context); + /* These are the real WGL/EGL context items that we will want to use later */ + gboolean debug_bit, compat_bit, legacy_bit; + /* These are the real WGL context items that we will want to use later */ HGLRC hglrc; gint pixel_format; - gboolean debug_bit, compat_bit, legacy_bit; + gboolean use_es = FALSE; /* request flags and specific versions for core (3.2+) WGL context */ gint flags = 0; - gint glver_major = 0; - gint glver_minor = 0; + gint major = 0; + gint minor = 0; + +#ifdef GDK_WIN32_ENABLE_EGL + EGLContext egl_context; +#endif GdkWindow *window = gdk_gl_context_get_window (context); GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl); GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (gdk_window_get_display (window)); - if (!_set_pixformat_for_hdc (context_win32->gl_hdc, - &pixel_format, - context_win32->need_alpha_bits, - win32_display)) - { - g_set_error_literal (error, GDK_GL_ERROR, - GDK_GL_ERROR_UNSUPPORTED_FORMAT, - _("No available configurations for the given pixel format")); - - return FALSE; - } - - gdk_gl_context_get_required_version (context, &glver_major, &glver_minor); - debug_bit = gdk_gl_context_get_debug_enabled (context); - compat_bit = gdk_gl_context_get_forward_compatible (context); - - /* if there isn't wglCreateContextAttribsARB(), or if GDK_GL_LEGACY is set, we default to a legacy context */ - legacy_bit = !win32_display->hasWglARBCreateContext || - g_getenv ("GDK_GL_LEGACY") != NULL; - /* * A legacy context cannot be shared with core profile ones, so this means we * must stick to a legacy context if the shared context is a legacy context */ - if (share != NULL && gdk_gl_context_is_legacy (share)) + if ((_gdk_gl_flags & GDK_GL_LEGACY) != 0 || + share != NULL && gdk_gl_context_is_legacy (share)) legacy_bit = TRUE; - if (debug_bit) - flags |= WGL_CONTEXT_DEBUG_BIT_ARB; - if (compat_bit) - flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + if ((_gdk_gl_flags & GDK_GL_GLES) != 0 || + (share != NULL && gdk_gl_context_get_use_es (share))) + use_es = TRUE; - GDK_NOTE (OPENGL, - g_print ("Creating %s WGL context (version:%d.%d, debug:%s, forward:%s, legacy: %s)\n", - compat_bit ? "core" : "compat", - glver_major, - glver_minor, - debug_bit ? "yes" : "no", - compat_bit ? "yes" : "no", - legacy_bit ? "yes" : "no")); - - hglrc = _create_gl_context (context_win32->gl_hdc, - share, - flags, - glver_major, - glver_minor, - &legacy_bit, - win32_display->hasWglARBCreateContext); - - if (hglrc == NULL) + gdk_gl_context_get_required_version (context, &major, &minor); + debug_bit = gdk_gl_context_get_debug_enabled (context); + compat_bit = gdk_gl_context_get_forward_compatible (context); + + if (win32_display->have_wgl) { - g_set_error_literal (error, GDK_GL_ERROR, - GDK_GL_ERROR_NOT_AVAILABLE, - _("Unable to create a GL context")); - return FALSE; + if (!_set_pixformat_for_hdc (context_win32->gl_hdc, + &pixel_format, + context_win32->need_alpha_bits, + win32_display)) + { + g_set_error_literal (error, GDK_GL_ERROR, + GDK_GL_ERROR_UNSUPPORTED_FORMAT, + _("No available configurations for the given pixel format")); + + return FALSE; + } + + /* if there isn't wglCreateContextAttribsARB(), or if GDK_GL_LEGACY is set, we default to a legacy context */ + legacy_bit = !win32_display->hasWglARBCreateContext || + g_getenv ("GDK_GL_LEGACY") != NULL; + + if (debug_bit) + flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + if (compat_bit) + flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + GDK_NOTE (OPENGL, + g_print ("Creating %s WGL context (version:%d.%d, debug:%s, forward:%s, legacy: %s)\n", + compat_bit ? "core" : "compat", + major, + minor, + debug_bit ? "yes" : "no", + compat_bit ? "yes" : "no", + legacy_bit ? "yes" : "no")); + + hglrc = _create_gl_context (context_win32->gl_hdc, + share, + flags, + major, + minor, + &legacy_bit, + win32_display->hasWglARBCreateContext); + + if (hglrc == NULL) + { + g_set_error_literal (error, GDK_GL_ERROR, + GDK_GL_ERROR_NOT_AVAILABLE, + _("Unable to create a GL context")); + return FALSE; + } + + GDK_NOTE (OPENGL, + g_print ("Created WGL context[%p], pixel_format=%d\n", + hglrc, + pixel_format)); + + context_win32->hglrc = hglrc; } - GDK_NOTE (OPENGL, - g_print ("Created WGL context[%p], pixel_format=%d\n", - hglrc, - pixel_format)); +#ifdef GDK_WIN32_ENABLE_EGL + if (win32_display->have_egl) + { + EGLContext ctx; + + if (debug_bit) + flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; + if (compat_bit) + flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; + + GDK_NOTE (OPENGL, g_message ("Creating EGL context version %d.%d (debug:%s, forward:%s, legacy:%s)", + major, minor, + debug_bit ? "yes" : "no", + compat_bit ? "yes" : "no", + legacy_bit ? "yes" : "no")); + + ctx = _create_egl_context (win32_display->egl_disp, + context_win32->egl_config, + share, + flags, + major, + minor, + &legacy_bit); + + if (ctx == EGL_NO_CONTEXT) + { + g_set_error_literal (error, GDK_GL_ERROR, + GDK_GL_ERROR_NOT_AVAILABLE, + _("Unable to create a GL context")); + + return FALSE; + } + + GDK_NOTE (OPENGL, + g_print ("Created EGL context[%p]\n", + ctx)); - context_win32->hglrc = hglrc; + context_win32->egl_context = ctx; + use_es = TRUE; + } +#endif + + /* set whether we are using GLES */ + gdk_gl_context_set_use_es(context, use_es); /* OpenGL does not work with WS_EX_LAYERED enabled, so we need to * disable WS_EX_LAYERED when we acquire a valid HGLRC @@ -804,9 +1113,21 @@ _gdk_win32_window_create_gl_context (GdkWindow *window, gboolean need_alpha_bits = (visual == gdk_screen_get_rgba_visual (gdk_display_get_default_screen (display))); /* Acquire and store up the Windows-specific HWND and HDC */ - HWND hwnd; HDC hdc; +#ifdef GDK_WIN32_ENABLE_EGL + EGLContext egl_context; + EGLConfig config; +#endif + + display_win32->gl_hwnd = GDK_WINDOW_HWND (window); + hdc = GetDC (display_win32->gl_hwnd); + +#ifdef GDK_WIN32_ENABLE_EGL + /* display_win32->hdc_egl_temp should *not* be destroyed here! It is destroyed at dispose()! */ + display_win32->hdc_egl_temp = hdc; +#endif + if (!_gdk_win32_display_init_gl (display, need_alpha_bits)) { g_set_error_literal (error, GDK_GL_ERROR, @@ -815,10 +1136,12 @@ _gdk_win32_window_create_gl_context (GdkWindow *window, return NULL; } - hwnd = GDK_WINDOW_HWND (window); - hdc = GetDC (hwnd); - - display_win32->gl_hwnd = hwnd; +#ifdef GDK_WIN32_ENABLE_EGL + if (display_win32->have_egl && !find_eglconfig_for_window (display_win32, &config, + &display_win32->egl_min_swap_interval, need_alpha_bits, + error)) + return NULL; +#endif context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT, "display", display, @@ -828,6 +1151,12 @@ _gdk_win32_window_create_gl_context (GdkWindow *window, context->need_alpha_bits = need_alpha_bits; context->gl_hdc = hdc; + +#ifdef GDK_WIN32_ENABLE_EGL + if (display_win32->have_egl) + context->egl_config = config; +#endif + context->is_attached = attached; return GDK_GL_CONTEXT (context); @@ -842,44 +1171,88 @@ _gdk_win32_display_make_gl_context_current (GdkDisplay *display, GdkWindow *window; GdkScreen *screen; +#if GDK_WIN32_ENABLE_EGL + EGLSurface egl_surface; +#endif + gboolean do_frame_sync = FALSE; if (context == NULL) { - wglMakeCurrent(NULL, NULL); + if (display_win32->have_wgl) + wglMakeCurrent(NULL, NULL); + +#ifdef GDK_WIN32_ENABLE_EGL + else if (display_win32->have_egl) + eglMakeCurrent (display_win32->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +#endif return TRUE; } context_win32 = GDK_WIN32_GL_CONTEXT (context); + window = gdk_gl_context_get_window (context); - if (!wglMakeCurrent (context_win32->gl_hdc, context_win32->hglrc)) + if (!gdk_gl_context_get_use_es (context)) { - GDK_NOTE (OPENGL, - g_print ("Making WGL context current failed\n")); - return FALSE; + if (!wglMakeCurrent (context_win32->gl_hdc, context_win32->hglrc)) + { + GDK_NOTE (OPENGL, + g_print ("Making WGL context current failed\n")); + return FALSE; + } + + if (context_win32->is_attached) + { + if (display_win32->hasWglEXTSwapControl) + { + /* If there is compositing there is no particular need to delay + * the swap when drawing on the offscreen, rendering to the screen + * happens later anyway, and its up to the compositor to sync that + * to the vblank. */ + screen = gdk_window_get_screen (window); + do_frame_sync = ! gdk_screen_is_composited (screen); + + if (do_frame_sync != context_win32->do_frame_sync) + { + context_win32->do_frame_sync = do_frame_sync; + + if (do_frame_sync) + wglSwapIntervalEXT (1); + else + wglSwapIntervalEXT (0); + } + } + } } - if (context_win32->is_attached && display_win32->hasWglEXTSwapControl) +#ifdef GDK_WIN32_ENABLE_EGL + else { - window = gdk_gl_context_get_window (context); - - /* If there is compositing there is no particular need to delay - * the swap when drawing on the offscreen, rendering to the screen - * happens later anyway, and its up to the compositor to sync that - * to the vblank. */ - screen = gdk_window_get_screen (window); - do_frame_sync = ! gdk_screen_is_composited (screen); - - if (do_frame_sync != context_win32->do_frame_sync) + if (context_win32->is_attached) + egl_surface = _gdk_win32_window_get_egl_surface (window, context_win32->egl_config, FALSE); + else { - context_win32->do_frame_sync = do_frame_sync; - - if (do_frame_sync) - wglSwapIntervalEXT (1); + if (display_win32->hasEglSurfacelessContext) + egl_surface = EGL_NO_SURFACE; else - wglSwapIntervalEXT (0); + egl_surface = _gdk_win32_window_get_egl_surface (window, context_win32->egl_config, TRUE); } + + if (!eglMakeCurrent (display_win32->egl_disp, + egl_surface, + egl_surface, + context_win32->egl_context)) + { + g_warning ("eglMakeCurrent failed"); + return FALSE; + } + + if (display_win32->egl_min_swap_interval == 0) + eglSwapInterval (display_win32->egl_disp, 0); + else + g_debug ("Can't disable GL swap interval"); } +#endif return TRUE; } @@ -901,18 +1274,38 @@ gdk_win32_display_get_wgl_version (GdkDisplay *display, gint *major, gint *minor) { + GdkWin32Display *display_win32 = NULL; g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE); if (!GDK_IS_WIN32_DISPLAY (display)) return FALSE; - if (!_gdk_win32_display_init_gl (display, FALSE)) + display_win32 = GDK_WIN32_DISPLAY (display); + + if (!_gdk_win32_display_init_gl (display, FALSE) || !display_win32->have_wgl +#ifdef GDK_WIN32_ENABLE_EGL + || !display_win32->have_egl +#endif + ) return FALSE; - if (major != NULL) - *major = GDK_WIN32_DISPLAY (display)->gl_version / 10; - if (minor != NULL) - *minor = GDK_WIN32_DISPLAY (display)->gl_version % 10; + if (display_win32->have_wgl) + { + if (major != NULL) + *major = GDK_WIN32_DISPLAY (display)->gl_version / 10; + if (minor != NULL) + *minor = GDK_WIN32_DISPLAY (display)->gl_version % 10; + } + +#ifdef GDK_WIN32_ENABLE_EGL + else if (display_win32->have_egl) + { + if (major != NULL) + *major = GDK_WIN32_DISPLAY (display)->egl_version / 10; + if (minor != NULL) + *minor = GDK_WIN32_DISPLAY (display)->egl_version % 10; + } +#endif return TRUE; } diff --git a/gdk/win32/gdkglcontext-win32.h b/gdk/win32/gdkglcontext-win32.h index b42cb9e220..f5535823f2 100644 --- a/gdk/win32/gdkglcontext-win32.h +++ b/gdk/win32/gdkglcontext-win32.h @@ -24,6 +24,10 @@ #include <epoxy/gl.h> #include <epoxy/wgl.h> +#ifdef GDK_WIN32_ENABLE_EGL +# include <epoxy/egl.h> +#endif + #include "gdkglcontextprivate.h" #include "gdkdisplayprivate.h" #include "gdkvisual.h" @@ -46,6 +50,12 @@ struct _GdkWin32GLContext guint is_attached : 1; guint do_frame_sync : 1; guint do_blit_swap : 1; + +#ifdef GDK_WIN32_ENABLE_EGL + /* EGL (Angle) Context Items */ + EGLContext egl_context; + EGLConfig egl_config; +#endif }; struct _GdkWin32GLContextClass diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index ea510e4bd4..2fd6ef2c5c 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -1074,6 +1074,7 @@ gdk_win32_window_destroy (GdkWindow *window, { GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (window->impl); GSList *tmp; + GdkWin32Display *display = NULL; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -1096,6 +1097,22 @@ gdk_win32_window_destroy (GdkWindow *window, g_slist_free (window_impl->transient_children); window_impl->transient_children = NULL; +#ifdef GDK_WIN32_ENABLE_EGL + display = GDK_WIN32_DISPLAY (gdk_window_get_display (window)); + + /* Get rid of any EGLSurfaces that we might have created */ + if (window_impl->egl_surface != EGL_NO_SURFACE) + { + eglDestroySurface (display->egl_disp, window_impl->egl_surface); + window_impl->egl_surface = EGL_NO_SURFACE; + } + if (window_impl->egl_dummy_surface != EGL_NO_SURFACE) + { + eglDestroySurface (display->egl_disp, window_impl->egl_dummy_surface); + window_impl->egl_dummy_surface = EGL_NO_SURFACE; + } +#endif + /* Remove ourself from our transient owner */ if (window_impl->transient_owner != NULL) { @@ -6276,3 +6293,35 @@ gdk_win32_window_get_handle (GdkWindow *window) return GDK_WINDOW_HWND (window); } + +#ifdef GDK_WIN32_ENABLE_EGL +EGLSurface +_gdk_win32_window_get_egl_surface (GdkWindow *window, + EGLConfig config, + gboolean is_dummy) +{ + EGLSurface surface; + GdkWin32Display *display = GDK_WIN32_DISPLAY (gdk_window_get_display (window)); + GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl); + + if (is_dummy) + { + if (impl->egl_dummy_surface == EGL_NO_SURFACE) + { + EGLint attribs[] = {EGL_WIDTH, 1, EGL_WIDTH, 1, EGL_NONE}; + impl->egl_dummy_surface = eglCreatePbufferSurface (display->egl_disp, + config, + attribs); + } + return impl->egl_dummy_surface; + } + else + { + if (impl->egl_surface == EGL_NO_SURFACE) + impl->egl_surface = eglCreateWindowSurface (display->egl_disp, config, display->gl_hwnd, NULL); + + return impl->egl_surface; + } + +} +#endif diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h index 59b9a42c39..a5e837ec8d 100644 --- a/gdk/win32/gdkwindow-win32.h +++ b/gdk/win32/gdkwindow-win32.h @@ -31,6 +31,10 @@ #include <windows.h> +#ifdef GDK_WIN32_ENABLE_EGL +#include <epoxy/egl.h> +#endif + G_BEGIN_DECLS /* Window implementation for Win32 @@ -352,6 +356,11 @@ struct _GdkWindowImplWin32 gint window_scale; gint unscaled_width; gint unscaled_height; + +#ifdef GDK_WIN32_ENABLE_EGL + EGLSurface egl_surface; + EGLSurface egl_dummy_surface; +#endif }; struct _GdkWindowImplWin32Class @@ -373,6 +382,12 @@ void _gdk_win32_window_update_style_bits (GdkWindow *window); gint _gdk_win32_window_get_scale_factor (GdkWindow *window); +#ifdef GDK_WIN32_ENABLE_EGL +EGLSurface _gdk_win32_window_get_egl_surface (GdkWindow *window, + EGLConfig config, + gboolean is_dummy); +#endif + G_END_DECLS #endif /* __GDK_WINDOW_WIN32_H__ */ |