From 12a23162b30f0329fbe0dbb2311ac28538349b2c Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Fri, 22 Jun 2018 15:02:24 +0800 Subject: [PATCH 1/5] build: Check for EGL support in libepoxy on Windows ...EGL support needs to be explicitly enabled during the build of libepoxy on Windows as it is not enabled by default on Windows. With this, we can add an EGL renderer for Windows that make use of Google's libANGLE, which is a library that translates OpenGL/ES calls to Direct3D 9/11, which will provide better hardware compatibility on Windows and would act as one of the foundations to resolve issue #105. --- gdk/win32/meson.build | 8 +++++++- meson.build | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/gdk/win32/meson.build b/gdk/win32/meson.build index 2a1cbe403b..1941fb7f3e 100644 --- a/gdk/win32/meson.build +++ b/gdk/win32/meson.build @@ -43,6 +43,12 @@ gdk_win32_public_headers = files([ install_headers(gdk_win32_public_headers, 'gdkwin32.h', subdir: 'gtk-4.0/gdk/win32/') +GDK_WIN32_EGL_CFLAGS = [] + +if win32_has_egl + GDK_WIN32_EGL_CFLAGS = ['-DGDK_WIN32_ENABLE_EGL'] +endif + gdk_win32_deps = [ # FIXME pangowin32_dep ] @@ -50,5 +56,5 @@ gdk_win32_deps = [ # FIXME libgdk_win32 = static_library('gdk-win32', gdk_win32_sources, gdkconfig, gdkenum_h, include_directories: [confinc, gdkinc], - c_args: ['-DGTK_COMPILATION', '-DG_LOG_DOMAIN="Gdk"', '-DINSIDE_GDK_WIN32'], + c_args: ['-DGTK_COMPILATION', '-DG_LOG_DOMAIN="Gdk"', '-DINSIDE_GDK_WIN32'] + GDK_WIN32_EGL_CFLAGS, dependencies: [gdk_deps, gdk_win32_deps]) diff --git a/meson.build b/meson.build index 71d7fd399f..7fa96b745c 100644 --- a/meson.build +++ b/meson.build @@ -607,6 +607,22 @@ if win32_enabled endif pc_gdk_extra_libs += ['-lwinmm', '-ldwmapi', '-lsetupapi', '-lcfgmgr32'] backend_immodules += ['ime'] + + # Check whether libepoxy is built with EGL support on Windows + win32_has_egl = cc.links( + ''' + #include + + int main(int argc, char *argv[]) + { + EGLDisplay disp = EGL_NO_DISPLAY; + + return epoxy_egl_version (disp); + } + ''', + dependencies : epoxy_dep, + name : 'libepoxy supports EGL on Windows' + ) endif # Check for bind_textdomain_codeset, including -lintl if GLib brings it in by From 257fd990d14488e8039a4f4511ee1efcfbf641f0 Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Tue, 31 Jul 2018 18:11:26 +0800 Subject: [PATCH 2/5] Add a EGL renderer (via ANGLE) for Windows This is for adding a EGL-based renderer which is done via the ANGLE project, which translate EGL calls to Direct3D 9/11. This is done as a possible solution to issue #105, especially for cases where the needed full GL extensions to map OpenGL to Direct3D is unavailable or unreliable, or when the OpenGL implementation from the graphics drivers are problematic. To enable this, do the following: -Build ANGLE and ensure the ANGLE libEGL.dll and libGLESv2.dll are available. A sufficiently-recent ANGLE is needed for things to work correctly--note that the copy of ANGLE that is included in qtbase-5.10.1 is sufficient. ANGLE is licensed under a BSD 3-clause license. -Build libepoxy on Windows with EGL support enabled. -Currently, prior to running GTK+ programs, the GDK_DEBUG envvar needs to be set with gl-gles as at least one of the flags. Known issues: -Only OpenGL ES 3 is supported, ANGLE's ES 2 does not support the needed extensions, notably GL_OES_vertex_array_object, but its ES 3 support is sufficient. -There is no autodetection or fallback mechanism to enable using EGL/Angle automatically yet. There are no plans to do this in this commit. --- gdk/gdkglcontext.c | 7 +- gdk/win32/gdkdisplay-win32.c | 11 + gdk/win32/gdkdisplay-win32.h | 18 + gdk/win32/gdkevents-win32.c | 7 +- gdk/win32/gdkglcontext-win32.c | 717 ++++++++++++++++++++++++++------- gdk/win32/gdkglcontext-win32.h | 12 + gdk/win32/gdksurface-win32.c | 65 ++- gdk/win32/gdksurface-win32.h | 16 + 8 files changed, 698 insertions(+), 155 deletions(-) diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index ecab21c51e..7e4554a6a1 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -993,11 +993,14 @@ 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; + priv->has_gl_framebuffer_blit = epoxy_has_gl_extension ("GL_ANGLE_framebuffer_blit"); /* No OES version */ priv->has_frame_terminator = FALSE; diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c index 5b76c95ac6..4c060437da 100644 --- a/gdk/win32/gdkdisplay-win32.c +++ b/gdk/win32/gdkdisplay-win32.c @@ -39,6 +39,9 @@ #include #include "gdkwin32langnotification.h" +#ifdef GDK_WIN32_ENABLE_EGL +# include +#endif static int debug_indent = 0; @@ -641,6 +644,14 @@ gdk_win32_display_dispose (GObject *object) { GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (object); +#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 bbb96fe255..0264ee82cd 100644 --- a/gdk/win32/gdkdisplay-win32.h +++ b/gdk/win32/gdkdisplay-win32.h @@ -24,6 +24,10 @@ #include "gdkwin32screen.h" #include "gdkwin32cursor.h" + +#ifdef GDK_WIN32_ENABLE_EGL +# include +#endif /* Define values used to set DPI-awareness */ typedef enum _GdkWin32ProcessDpiAwareness { @@ -82,6 +86,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 + GListModel *monitors; guint hasWglARBCreateContext : 1; @@ -90,6 +102,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/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 67a52e69b1..128b13ae25 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -51,6 +51,7 @@ #include "gdkmonitorprivate.h" #include "gdkwin32.h" #include "gdkkeysyms.h" +#include "gdkglcontext-win32.h" #include "gdkdevicemanager-win32.h" #include "gdkdisplay-win32.h" #include "gdkdeviceprivate.h" @@ -2945,7 +2946,11 @@ gdk_event_translate (MSG *msg, { case SC_MINIMIZE: case SC_RESTORE: - do_show_window (window, msg->wParam == SC_MINIMIZE ? TRUE : FALSE); + do_show_window (window, msg->wParam == SC_MINIMIZE ? TRUE : FALSE); + + if (msg->wParam == SC_RESTORE) + _gdk_win32_surface_invalidate_egl_framebuffer (window); + break; case SC_MAXIMIZE: impl = GDK_WIN32_SURFACE (window); diff --git a/gdk/win32/gdkglcontext-win32.c b/gdk/win32/gdkglcontext-win32.c index 9aee9b2391..6fffbc38e5 100644 --- a/gdk/win32/gdkglcontext-win32.c +++ b/gdk/win32/gdkglcontext-win32.c @@ -41,6 +41,10 @@ #include #include +#ifdef GDK_WIN32_ENABLE_EGL +# include +#endif + G_DEFINE_TYPE (GdkWin32GLContext, gdk_win32_gl_context, GDK_TYPE_GL_CONTEXT) static void @@ -51,17 +55,37 @@ _gdk_win32_gl_context_dispose (GObject *gobject) GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)); GdkSurface *surface = gdk_gl_context_get_surface (context); - if (context_win32->hglrc != NULL) + if (display_win32 != NULL) { - if (wglGetCurrentContext () == context_win32->hglrc) - wglMakeCurrent (NULL, NULL); + if (display_win32->have_wgl) + { + if (wglGetCurrentContext () == context_win32->hglrc) + wglMakeCurrent (NULL, NULL); - GDK_NOTE (OPENGL, g_print ("Destroying WGL context\n")); + GDK_NOTE (OPENGL, g_print ("Destroying WGL context\n")); - wglDeleteContext (context_win32->hglrc); - context_win32->hglrc = NULL; + wglDeleteContext (context_win32->hglrc); + context_win32->hglrc = NULL; - ReleaseDC (display_win32->gl_hwnd, context_win32->gl_hdc); + ReleaseDC (display_win32->gl_hwnd, context_win32->gl_hdc); + } + +#ifdef GDK_WIN32_ENABLE_EGL + else if (display_win32->have_egl) + { + 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; + + ReleaseDC (display_win32->gl_hwnd, context_win32->gl_hdc); + } +#endif } if (surface != NULL) @@ -77,7 +101,6 @@ _gdk_win32_gl_context_dispose (GObject *gobject) if (impl->suppress_layered == 0) _gdk_win32_surface_update_style_bits (surface); } - G_OBJECT_CLASS (gdk_win32_gl_context_parent_class)->dispose (gobject); } @@ -100,6 +123,33 @@ gdk_gl_blit_region (GdkSurface *surface, cairo_region_t *region) } } +#ifdef GDK_WIN32_ENABLE_EGL +static gboolean +_get_is_egl_force_redraw (GdkSurface *surface) +{ + /* We only need to call gdk_window_invalidate_rect () if necessary */ + if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context)) + { + GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface); + + return impl->egl_force_redraw_all; + } + return FALSE; +} + +static void +_reset_egl_force_redraw (GdkSurface *surface) +{ + if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context)) + { + GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface); + + if (impl->egl_force_redraw_all) + impl->egl_force_redraw_all = FALSE; + } +} +#endif + static void gdk_win32_gl_context_end_frame (GdkDrawContext *draw_context, cairo_region_t *painted) @@ -108,7 +158,6 @@ gdk_win32_gl_context_end_frame (GdkDrawContext *draw_context, GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context); GdkSurface *surface = gdk_gl_context_get_surface (context); GdkWin32Display *display = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context))); - gboolean can_wait = display->hasWglOMLSyncControl; cairo_rectangle_int_t whole_window; GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_parent_class)->end_frame (draw_context, painted); @@ -116,9 +165,12 @@ gdk_win32_gl_context_end_frame (GdkDrawContext *draw_context, return; gdk_gl_context_make_current (context); + whole_window = (GdkRectangle) { 0, 0, gdk_surface_get_width (surface), gdk_surface_get_height (surface) }; - 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 (); @@ -135,29 +187,48 @@ gdk_win32_gl_context_end_frame (GdkDrawContext *draw_context, &ust, &msc, &sbc); } } - } - whole_window = (GdkRectangle) { 0, 0, gdk_surface_get_width (surface), gdk_surface_get_height (surface) }; - if (cairo_region_contains_rectangle (painted, &whole_window) == CAIRO_REGION_OVERLAP_IN) - { - SwapBuffers (context_win32->gl_hdc); - } - else if (gdk_gl_context_has_framebuffer_blit (context)) - { - glDrawBuffer(GL_FRONT); - glReadBuffer(GL_BACK); - gdk_gl_blit_region (surface, painted); - glDrawBuffer(GL_BACK); - glFlush(); + if (cairo_region_contains_rectangle (painted, &whole_window) == CAIRO_REGION_OVERLAP_IN) + SwapBuffers (context_win32->gl_hdc); + else if (gdk_gl_context_has_framebuffer_blit (context)) + { + glDrawBuffer(GL_FRONT); + glReadBuffer(GL_BACK); + gdk_gl_blit_region (surface, painted); + glDrawBuffer(GL_BACK); + glFlush(); - if (gdk_gl_context_has_frame_terminator (context)) - glFrameTerminatorGREMEDY (); + if (gdk_gl_context_has_frame_terminator (context)) + glFrameTerminatorGREMEDY (); + } + else + { + g_warning ("Need to swap whole buffer even thouigh not everything was redrawn. Expect artifacts."); + SwapBuffers (context_win32->gl_hdc); + } } +#ifdef GDK_WIN32_ENABLE_EGL else { - g_warning ("Need to swap whole buffer even thouigh not everything was redrawn. Expect artifacts."); - SwapBuffers (context_win32->gl_hdc); + EGLSurface egl_surface = _gdk_win32_surface_get_egl_surface (surface, context_win32->egl_config, FALSE); + gboolean force_egl_redraw_all = _get_is_egl_force_redraw (surface); + + if (!force_egl_redraw_all) + gdk_gl_blit_region (surface, painted); + else if (force_egl_redraw_all) + { + GdkRectangle rect = {0, 0, gdk_surface_get_width (surface), gdk_surface_get_height (surface)}; + + /* We need to do gdk_window_invalidate_rect() so that we don't get glitches after maximizing or + * restoring or using aerosnap + */ + gdk_surface_invalidate_rect (surface, &rect); + _reset_egl_force_redraw (surface); + } + + eglSwapBuffers (display->egl_disp, egl_surface); } +#endif } static void @@ -415,61 +486,150 @@ _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) { GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display); int 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_DISPLAY_DEBUG_CHECK (display, GL_GLES); +#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) + { + GdkWGLDummy dummy; + memset (&dummy, 0, sizeof (GdkWGLDummy)); - /* 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); + /* 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); - 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->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"); + 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" + 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); + _destroy_dummy_gl_context (dummy); + } +#ifdef GDK_WIN32_ENABLE_EGL + else + { + 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"); + + GDK_NOTE (OPENGL, + 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")); + } +#endif return TRUE; } @@ -649,6 +809,122 @@ _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, + 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; + attrs[i++] = EGL_ALPHA_SIZE; + attrs[i++] = 1; + + 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 */ + static gboolean gdk_win32_gl_context_realize (GdkGLContext *context, GError **error) @@ -656,39 +932,23 @@ 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 context items that we will want to use later */ - HGLRC hglrc; - int pixel_format; gboolean debug_bit, compat_bit, legacy_bit; + gboolean use_es = FALSE; /* request flags and specific versions for core (3.2+) WGL context */ int flags = 0; - int glver_major = 0; - int glver_minor = 0; + int major = 0; + int minor = 0; GdkSurface *surface = gdk_gl_context_get_surface (context); GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface); - GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (gdk_surface_get_display (surface)); + GdkDisplay *display = gdk_surface_get_display (surface); + GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display); - if (!_set_pixformat_for_hdc (context_win32->gl_hdc, - &pixel_format, - 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); + 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 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 @@ -696,42 +956,114 @@ gdk_win32_gl_context_realize (GdkGLContext *context, if (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_LEGACY is set, we default to a legacy context */ + legacy_bit = g_getenv ("GDK_GL_LEGACY") != NULL; - 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")); + use_es = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) || + (share != NULL && gdk_gl_context_get_use_es (share)); - hglrc = _create_gl_context (context_win32->gl_hdc, - share, - flags, - glver_major, - glver_minor, - &legacy_bit, - win32_display->hasWglARBCreateContext); - - if (hglrc == NULL) + if (win32_display->have_wgl || !use_es) { - g_set_error_literal (error, GDK_GL_ERROR, - GDK_GL_ERROR_NOT_AVAILABLE, - _("Unable to create a GL context")); - return FALSE; + /* These are the real WGL context items that we will want to use later */ + HGLRC hglrc; + int pixel_format; + + if (!_set_pixformat_for_hdc (context_win32->gl_hdc, + &pixel_format, + 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() on WGL, use a legacy context */ + if (!legacy_bit) + legacy_bit = !win32_display->hasWglARBCreateContext; + 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 + else + { + EGLContext egl_context; + EGLContext ctx; - context_win32->hglrc = hglrc; + 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->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 @@ -781,9 +1113,22 @@ _gdk_win32_surface_create_gl_context (GdkSurface *surface, GdkWin32GLContext *context = NULL; /* Acquire and store up the Windows-specific HWND and HDC */ - HWND hwnd; +/* HWND hwnd;*/ HDC hdc; +#ifdef GDK_WIN32_ENABLE_EGL + EGLContext egl_context; + EGLConfig config; +#endif + + display_win32->gl_hwnd = GDK_SURFACE_HWND (surface); + 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)) { g_set_error_literal (error, GDK_GL_ERROR, @@ -792,10 +1137,21 @@ _gdk_win32_surface_create_gl_context (GdkSurface *surface, return NULL; } - hwnd = GDK_SURFACE_HWND (surface); - hdc = GetDC (hwnd); +#if 0 + if (display_win32->have_wgl) + { + hwnd = GDK_SURFACE_HWND (surface); + hdc = GetDC (hwnd); - display_win32->gl_hwnd = hwnd; + display_win32->gl_hwnd = hwnd; + } +#endif + +#ifdef GDK_WIN32_ENABLE_EGL + if (display_win32->have_egl && !find_eglconfig_for_window (display_win32, &config, + &display_win32->egl_min_swap_interval, error)) + return NULL; +#endif context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT, "surface", surface, @@ -805,6 +1161,11 @@ _gdk_win32_surface_create_gl_context (GdkSurface *surface, context->gl_hdc = hdc; context->is_attached = attached; +#ifdef GDK_WIN32_ENABLE_EGL + if (display_win32->have_egl) + context->egl_config = config; +#endif + return GDK_GL_CONTEXT (context); } @@ -820,41 +1181,86 @@ _gdk_win32_display_make_gl_context_current (GdkDisplay *display, if (context == NULL) { - wglMakeCurrent(NULL, NULL); +#ifdef GDK_WIN32_ENABLE_EGL + if (display_win32->egl_disp != EGL_NO_DISPLAY) + eglMakeCurrent(display_win32->egl_disp, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT); + else +#endif + wglMakeCurrent(NULL, NULL); + return TRUE; } context_win32 = GDK_WIN32_GL_CONTEXT (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 (context_win32->is_attached && display_win32->hasWglEXTSwapControl) - { - surface = gdk_gl_context_get_surface (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. */ - display = gdk_surface_get_display (surface); - do_frame_sync = ! gdk_display_is_composited (display); - - if (do_frame_sync != context_win32->do_frame_sync) + if (!wglMakeCurrent (context_win32->gl_hdc, context_win32->hglrc)) { - context_win32->do_frame_sync = do_frame_sync; + GDK_NOTE (OPENGL, + g_print ("Making WGL context current failed\n")); + return FALSE; + } - if (do_frame_sync) - wglSwapIntervalEXT (1); - else - wglSwapIntervalEXT (0); + if (context_win32->is_attached && display_win32->hasWglEXTSwapControl) + { + surface = gdk_gl_context_get_surface (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. */ + display = gdk_surface_get_display (surface); + do_frame_sync = ! gdk_display_is_composited (display); + + 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); + } } } +#ifdef GDK_WIN32_ENABLE_EGL + else + { + EGLSurface egl_surface; + + surface = gdk_gl_context_get_surface (context); + + if (context_win32->is_attached) + egl_surface = _gdk_win32_surface_get_egl_surface (surface, context_win32->egl_config, FALSE); + else + { + if (display_win32->hasEglSurfacelessContext) + egl_surface = EGL_NO_SURFACE; + else + egl_surface = _gdk_win32_surface_get_egl_surface (surface, 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; } @@ -888,3 +1294,20 @@ gdk_win32_display_get_wgl_version (GdkDisplay *display, return TRUE; } + +void +_gdk_win32_surface_invalidate_egl_framebuffer (GdkSurface *surface) +{ +/* If we are using ANGLE, we need to force redraw of the whole Window and its child windows + * as we need to re-acquire the EGL surfaces that we rendered to upload to Cairo explicitly, + * using gdk_window_invalidate_rect (), when we maximize or restore or use aerosnap + */ +#ifdef GDK_WIN32_ENABLE_EGL + if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context)) + { + GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface); + + impl->egl_force_redraw_all = TRUE; + } +#endif +} diff --git a/gdk/win32/gdkglcontext-win32.h b/gdk/win32/gdkglcontext-win32.h index 8549679559..3249d4c6db 100644 --- a/gdk/win32/gdkglcontext-win32.h +++ b/gdk/win32/gdkglcontext-win32.h @@ -24,6 +24,10 @@ #include #include +#ifdef GDK_WIN32_ENABLE_EGL +# include +#endif + #include "gdkglcontextprivate.h" #include "gdkdisplayprivate.h" #include "gdksurface.h" @@ -43,6 +47,12 @@ struct _GdkWin32GLContext /* other items */ guint is_attached : 1; guint do_frame_sync : 1; + +#ifdef GDK_WIN32_ENABLE_EGL + /* EGL (Angle) Context Items */ + EGLContext egl_context; + EGLConfig egl_config; +#endif }; struct _GdkWin32GLContextClass @@ -59,6 +69,8 @@ _gdk_win32_surface_create_gl_context (GdkSurface *window, gboolean _gdk_win32_display_make_gl_context_current (GdkDisplay *display, GdkGLContext *context); +void +_gdk_win32_surface_invalidate_egl_framebuffer (GdkSurface *surface); G_END_DECLS diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c index 4ae96c7c62..1862fdf098 100644 --- a/gdk/win32/gdksurface-win32.c +++ b/gdk/win32/gdksurface-win32.c @@ -711,6 +711,22 @@ gdk_win32_surface_destroy (GdkSurface *window, gdk_win32_surface_set_transient_for (child, NULL); } +#ifdef GDK_WIN32_ENABLE_EGL + GdkWin32Display *display = GDK_WIN32_DISPLAY (gdk_surface_get_display (window)); + + /* Get rid of any EGLSurfaces that we might have created */ + if (surface->egl_surface != EGL_NO_SURFACE) + { + eglDestroySurface (display->egl_disp, surface->egl_surface); + surface->egl_surface = EGL_NO_SURFACE; + } + if (surface->egl_dummy_surface != EGL_NO_SURFACE) + { + eglDestroySurface (display->egl_disp, surface->egl_dummy_surface); + surface->egl_dummy_surface = EGL_NO_SURFACE; + } +#endif + /* Remove ourself from our transient owner */ if (surface->transient_owner != NULL) { @@ -1253,14 +1269,16 @@ gdk_win32_surface_move_resize_internal (GdkSurface *window, } else { + _gdk_win32_surface_invalidate_egl_framebuffer (window); + if (with_move) - { + { gdk_win32_surface_do_move_resize (window, x, y, width, height); - } + } else - { - gdk_win32_surface_resize (window, width, height); - } + { + gdk_win32_surface_resize (window, width, height); + } } out: @@ -3809,6 +3827,9 @@ gdk_win32_surface_end_move_resize_drag (GdkSurface *window) { GdkWin32Surface *impl = GDK_WIN32_SURFACE (window); GdkW32DragMoveResizeContext *context = &impl->drag_move_resize_context; + + if (context->op == GDK_WIN32_DRAGOP_RESIZE) + _gdk_win32_surface_invalidate_egl_framebuffer (window); context->op = GDK_WIN32_DRAGOP_NONE; @@ -4286,6 +4307,8 @@ gdk_win32_surface_unmaximize (GdkSurface *window) GDK_SURFACE_HWND (window), _gdk_win32_surface_state_to_string (window->state))); + _gdk_win32_surface_invalidate_egl_framebuffer (window); + if (GDK_SURFACE_IS_MAPPED (window)) GtkShowWindow (window, SW_RESTORE); else @@ -4362,6 +4385,7 @@ gdk_win32_surface_unfullscreen (GdkSurface *window) impl->hint_flags = fi->hint_flags; SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE, fi->style); + _gdk_win32_surface_invalidate_egl_framebuffer (window); API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_NOTOPMOST, fi->r.left, fi->r.top, fi->r.right - fi->r.left, fi->r.bottom - fi->r.top, @@ -5140,3 +5164,34 @@ gdk_win32_drag_surface_iface_init (GdkDragSurfaceInterface *iface) { iface->present = gdk_win32_drag_surface_present; } + +#ifdef GDK_WIN32_ENABLE_EGL +EGLSurface +_gdk_win32_surface_get_egl_surface (GdkSurface *surface, + EGLConfig config, + gboolean is_dummy) +{ + GdkWin32Display *display = GDK_WIN32_DISPLAY (gdk_surface_get_display (surface)); + GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface); + + 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/gdksurface-win32.h b/gdk/win32/gdksurface-win32.h index 649e29c869..e4f97d11be 100644 --- a/gdk/win32/gdksurface-win32.h +++ b/gdk/win32/gdksurface-win32.h @@ -34,6 +34,10 @@ #include +#ifdef GDK_WIN32_ENABLE_EGL +# include +#endif + G_BEGIN_DECLS typedef enum @@ -351,6 +355,12 @@ struct _GdkWin32Surface int surface_scale; int unscaled_width; int unscaled_height; + +#ifdef GDK_WIN32_ENABLE_EGL + EGLSurface egl_surface; + EGLSurface egl_dummy_surface; + guint egl_force_redraw_all : 1; +#endif }; struct _GdkWin32SurfaceClass @@ -392,6 +402,12 @@ void gdk_win32_surface_apply_queued_move_resize (GdkSurface *surface, RECT window_rect); +#ifdef GDK_WIN32_ENABLE_EGL +EGLSurface _gdk_win32_surface_get_egl_surface (GdkSurface *surface, + EGLConfig config, + gboolean is_dummy); +#endif + G_END_DECLS #endif /* __GDK_SURFACE_WIN32_H__ */ From e5600ab99b9fba4c8f37773ce4a599aea7ff2c67 Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Fri, 3 Aug 2018 15:54:48 +0800 Subject: [PATCH 3/5] demos: Fix glarea demo on OpenGL/ES Some implementations of the ES 1.00 shader (such as Google's ANGLE) do not like the 'f' suffix for floats, so just drop it, as it should be harmless to drop. --- demos/gtk-demo/glarea-gles.fs.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demos/gtk-demo/glarea-gles.fs.glsl b/demos/gtk-demo/glarea-gles.fs.glsl index 39f7143960..ac5e195031 100644 --- a/demos/gtk-demo/glarea-gles.fs.glsl +++ b/demos/gtk-demo/glarea-gles.fs.glsl @@ -1,7 +1,7 @@ precision highp float; void main() { - float lerpVal = gl_FragCoord.y / 500.0f; + float lerpVal = gl_FragCoord.y / 500.0; - gl_FragColor = mix(vec4(1.0f, 0.85f, 0.35f, 1.0f), vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpVal); + gl_FragColor = mix(vec4(1.0, 0.85, 0.35, 1.0), vec4(0.2, 0.2, 0.2, 1.0), lerpVal); } From cf0175ffcec21ebc7b74c1fc44e74437e30af840 Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Tue, 31 Jul 2018 18:18:59 +0800 Subject: [PATCH 4/5] OpenGL/ES: Fix 'R' and 'B' bits inverted on Windows We need to use GL_BGRA instead of GL_RGBA when doing glReadPixels() on EGL on Windows (ANGLE) so that the red and blue bits won't be displayed inverted. Also fix the logic where we determine whether to bit blit or redraw everything. --- gdk/gdkgl.c | 4 +++- gdk/gdkglcontext.c | 20 ++++++++++++++++++++ gdk/gdkglcontextprivate.h | 3 +++ gdk/win32/gdkglcontext-win32.c | 14 ++++++++++---- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/gdk/gdkgl.c b/gdk/gdkgl.c index 6ea045b9b0..309f792613 100644 --- a/gdk/gdkgl.c +++ b/gdk/gdkgl.c @@ -334,6 +334,7 @@ gdk_cairo_draw_from_gl (cairo_t *cr, cairo_region_t *clip_region; GdkGLContextPaintData *paint_data; int major, minor, version; + gboolean es_use_bgra = FALSE; paint_context = gdk_surface_get_paint_gl_context (surface, NULL); if (paint_context == NULL) @@ -343,6 +344,7 @@ gdk_cairo_draw_from_gl (cairo_t *cr, } clip_region = gdk_cairo_region_from_clip (cr); + es_use_bgra = gdk_gl_context_use_es_bgra (paint_context); gdk_gl_context_make_current (paint_context); paint_data = gdk_gl_context_get_paint_data (paint_context); @@ -413,7 +415,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_use_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 7e4554a6a1..a7284b27c6 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -92,6 +92,10 @@ #include "gdkintl.h" #include "gdk-private.h" +#ifdef GDK_WINDOWING_WIN32 +# include "gdk/win32/gdkwin32.h" +#endif + #include typedef struct { @@ -1226,3 +1230,19 @@ gdk_gl_context_has_debug (GdkGLContext *self) return priv->debug_enabled || priv->use_khr_debug; } + +/* This is currently private! */ +/* When using GL/ES, don't flip the 'R' and 'B' bits on Windows/ANGLE for glReadPixels() */ +gboolean +gdk_gl_context_use_es_bgra (GdkGLContext *context) +{ + if (!gdk_gl_context_get_use_es (context)) + return FALSE; + +#ifdef GDK_WINDOWING_WIN32 + if (GDK_WIN32_IS_GL_CONTEXT (context)) + return TRUE; +#endif + + return FALSE; +} diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h index c289c144f3..bf2dbfa5ff 100644 --- a/gdk/gdkglcontextprivate.h +++ b/gdk/gdkglcontextprivate.h @@ -107,6 +107,9 @@ void gdk_gl_context_label_object_printf (GdkGLContext ...) G_GNUC_PRINTF (4, 5); gboolean gdk_gl_context_has_debug (GdkGLContext *self) G_GNUC_PURE; + +gboolean gdk_gl_context_use_es_bgra (GdkGLContext *context); + G_END_DECLS #endif /* __GDK_GL_CONTEXT_PRIVATE_H__ */ diff --git a/gdk/win32/gdkglcontext-win32.c b/gdk/win32/gdkglcontext-win32.c index 6fffbc38e5..d52c16e2cb 100644 --- a/gdk/win32/gdkglcontext-win32.c +++ b/gdk/win32/gdkglcontext-win32.c @@ -213,9 +213,7 @@ gdk_win32_gl_context_end_frame (GdkDrawContext *draw_context, EGLSurface egl_surface = _gdk_win32_surface_get_egl_surface (surface, context_win32->egl_config, FALSE); gboolean force_egl_redraw_all = _get_is_egl_force_redraw (surface); - if (!force_egl_redraw_all) - gdk_gl_blit_region (surface, painted); - else if (force_egl_redraw_all) + if (force_egl_redraw_all) { GdkRectangle rect = {0, 0, gdk_surface_get_width (surface), gdk_surface_get_height (surface)}; @@ -226,7 +224,15 @@ gdk_win32_gl_context_end_frame (GdkDrawContext *draw_context, _reset_egl_force_redraw (surface); } - eglSwapBuffers (display->egl_disp, egl_surface); + if (cairo_region_contains_rectangle (painted, &whole_window) == CAIRO_REGION_OVERLAP_IN || force_egl_redraw_all) + eglSwapBuffers (display->egl_disp, egl_surface); + else if (gdk_gl_context_has_framebuffer_blit (context)) + gdk_gl_blit_region (surface, painted); + else + { + g_warning ("Need to swap whole buffer even thouigh not everything was redrawn. Expect artifacts."); + eglSwapBuffers (display->egl_disp, egl_surface); + } } #endif } From a481733b400a43d34a9587b2c1d2bb1aa6d8447b Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Tue, 7 May 2019 00:09:03 -0700 Subject: [PATCH 5/5] GDK/Win32: Force GLES if running on ARM64 If GLES support is enabled on Windows, force GLES mode if we are running on a ARM64 version of Windows (i.e. Windows 10 for ARM). This is required as ARM64 versions of Windows only provide a software implementation of OpenGL 1.1/1.2, which is not enough for our purposes. Thus, we could make instead use the GLES support provided via Google's libANGLE (which emulates OpenGL/ES 3 with Direct3D 9/11), so that we can run GtkGLArea programs under OpenGL/ES in ARM64 versions of Windows. Note that eventually we could update the libepoxy build files for Windows to not check nor enable WGL when building for ARM64 Windows, as the WGL items do not work, although they do build. --- gdk/win32/gdkdisplay-win32.c | 39 ++++++++++++++++++++++++++++++++++ gdk/win32/gdkdisplay-win32.h | 11 ++++++++++ gdk/win32/gdkglcontext-win32.c | 3 ++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c index 4c060437da..a1c0b26e0b 100644 --- a/gdk/win32/gdkdisplay-win32.c +++ b/gdk/win32/gdkdisplay-win32.c @@ -43,6 +43,10 @@ # include #endif +#ifndef IMAGE_FILE_MACHINE_ARM64 +# define IMAGE_FILE_MACHINE_ARM64 0xAA64 +#endif + static int debug_indent = 0; /** @@ -880,6 +884,40 @@ _gdk_win32_enable_hidpi (GdkWin32Display *display) } } +static void +_gdk_win32_check_on_arm64 (GdkWin32Display *display) +{ + static gsize checked = 0; + + if (g_once_init_enter (&checked)) + { + HMODULE kernel32 = LoadLibraryW (L"kernel32.dll"); + + if (kernel32 != NULL) + { + display->cpu_funcs.isWow64Process2 = + (funcIsWow64Process2) GetProcAddress (kernel32, "IsWow64Process2"); + + if (display->cpu_funcs.isWow64Process2 != NULL) + { + USHORT proc_cpu = 0; + USHORT native_cpu = 0; + + display->cpu_funcs.isWow64Process2 (GetCurrentProcess (), + &proc_cpu, + &native_cpu); + + if (native_cpu == IMAGE_FILE_MACHINE_ARM64) + display->running_on_arm64 = TRUE; + } + + FreeLibrary (kernel32); + } + + g_once_init_leave (&checked, 1); + } +} + static void gdk_win32_display_init (GdkWin32Display *display) { @@ -888,6 +926,7 @@ gdk_win32_display_init (GdkWin32Display *display) display->monitors = G_LIST_MODEL (g_list_store_new (GDK_TYPE_MONITOR)); _gdk_win32_enable_hidpi (display); + _gdk_win32_check_on_arm64 (display); /* if we have DPI awareness, set up fixed scale if set */ if (display->dpi_aware_type != PROCESS_DPI_UNAWARE && diff --git a/gdk/win32/gdkdisplay-win32.h b/gdk/win32/gdkdisplay-win32.h index 0264ee82cd..b9bfaeb2e1 100644 --- a/gdk/win32/gdkdisplay-win32.h +++ b/gdk/win32/gdkdisplay-win32.h @@ -69,6 +69,13 @@ typedef struct _GdkWin32User32DPIFuncs funcIsProcessDPIAware isDpiAwareFunc; } GdkWin32User32DPIFuncs; +/* Detect running architecture */ +typedef BOOL (WINAPI *funcIsWow64Process2) (HANDLE, USHORT *, USHORT *); +typedef struct _GdkWin32KernelCPUFuncs +{ + funcIsWow64Process2 isWow64Process2; +} GdkWin32KernelCPUFuncs; + struct _GdkWin32Display { GdkDisplay display; @@ -131,6 +138,10 @@ struct _GdkWin32Display /* Message filters */ GList *filters; + + /* Running CPU items */ + guint running_on_arm64 : 1; + GdkWin32KernelCPUFuncs cpu_funcs; }; struct _GdkWin32DisplayClass diff --git a/gdk/win32/gdkglcontext-win32.c b/gdk/win32/gdkglcontext-win32.c index d52c16e2cb..056b651355 100644 --- a/gdk/win32/gdkglcontext-win32.c +++ b/gdk/win32/gdkglcontext-win32.c @@ -540,7 +540,8 @@ _gdk_win32_display_init_gl (GdkDisplay *display) #ifdef GDK_WIN32_ENABLE_EGL EGLDisplay egl_disp; - disable_wgl = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES); + disable_wgl = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) || + display_win32->running_on_arm64; #endif if (display_win32->have_wgl