diff options
Diffstat (limited to 'gdk')
-rw-r--r-- | gdk/gdkglcontext.c | 7 | ||||
-rw-r--r-- | gdk/win32/gdkdisplay-win32.c | 12 | ||||
-rw-r--r-- | gdk/win32/gdkdisplay-win32.h | 18 | ||||
-rw-r--r-- | gdk/win32/gdkevents-win32.c | 7 | ||||
-rw-r--r-- | gdk/win32/gdkglcontext-win32.c | 720 | ||||
-rw-r--r-- | gdk/win32/gdkglcontext-win32.h | 12 | ||||
-rw-r--r-- | gdk/win32/gdksurface-win32.c | 66 | ||||
-rw-r--r-- | gdk/win32/gdksurface-win32.h | 15 |
8 files changed, 701 insertions, 156 deletions
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index d443a83cf8..00f56fcf0c 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -886,11 +886,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 4a7182758f..e9b63b181f 100644 --- a/gdk/win32/gdkdisplay-win32.c +++ b/gdk/win32/gdkdisplay-win32.c @@ -38,6 +38,10 @@ #include <dwmapi.h> +#ifdef GDK_WIN32_ENABLE_EGL +# include <epoxy/egl.h> +#endif + static int debug_indent = 0; /** @@ -676,6 +680,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 a4d9cc7378..fd904068a4 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 <epoxy/egl.h> +#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 + GPtrArray *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 6017f605b2..e7a09f2f54 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" @@ -2898,7 +2899,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_SURFACE_IMPL_WIN32 (window->impl); diff --git a/gdk/win32/gdkglcontext-win32.c b/gdk/win32/gdkglcontext-win32.c index 4845f4ba16..2454d931b0 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 @@ -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")); + + wglDeleteContext (context_win32->hglrc); + context_win32->hglrc = NULL; + + 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_print ("Destroying WGL context\n")); + GDK_NOTE (OPENGL, g_message ("Destroying EGL (ANGLE) context")); - wglDeleteContext (context_win32->hglrc); - context_win32->hglrc = NULL; + 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); + ReleaseDC (display_win32->gl_hwnd, context_win32->gl_hdc); + } +#endif } if (surface != NULL && surface->impl != 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,35 @@ gdk_gl_blit_region (GdkSurface *surface, cairo_region_t *region) } } +static gboolean +_get_is_egl_force_redraw (GdkSurface *surface) +{ + /* We only need to call gdk_window_invalidate_rect () if necessary */ +#ifdef GDK_WIN32_ENABLE_EGL + if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context)) + { + GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (surface->impl); + + return impl->egl_force_redraw_all; + } +#endif + return FALSE; +} + +static void +_reset_egl_force_redraw (GdkSurface *surface) +{ +#ifdef GDK_WIN32_ENABLE_EGL + if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context)) + { + GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (surface->impl); + + 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 +160,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 +167,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 +189,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 (gdk_gl_context_has_frame_terminator (context)) - glFrameTerminatorGREMEDY (); + 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 (); + } + 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 @@ -395,61 +468,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); 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_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->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); + _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->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" + + 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; } @@ -629,6 +791,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) @@ -636,39 +914,24 @@ 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; - gint pixel_format; + /* These are the real WGL/EGL context items that we will want to use later */ 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; GdkSurface *surface = gdk_gl_context_get_surface (context); GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (surface->impl); - GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (gdk_surface_get_display (surface)); - - 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; - } + GdkDisplay *display = gdk_surface_get_display (surface); + GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display); - 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 @@ -676,42 +939,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; - - 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) + /* if GDK_GL_LEGACY is set, we default to a legacy context */ + legacy_bit = g_getenv ("GDK_GL_LEGACY") != NULL; + + use_es = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) || + (share != NULL && gdk_gl_context_get_use_es (share)); + + 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; + gint 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; + + 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 - context_win32->hglrc = hglrc; + /* 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 @@ -761,9 +1096,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, @@ -772,10 +1120,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; + } +#endif - 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, error)) + return NULL; +#endif context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT, "surface", surface, @@ -785,6 +1144,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); } @@ -800,40 +1164,85 @@ _gdk_win32_display_make_gl_context_current (GdkDisplay *display, if (context == NULL) { - wglMakeCurrent(NULL, NULL); + if (!gdk_gl_context_get_use_es (context)) + wglMakeCurrent(NULL, NULL); + +#ifdef GDK_WIN32_ENABLE_EGL + else + eglMakeCurrent(display_win32->egl_disp, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT); +#endif 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 (!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 && 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); + } + } } - if (context_win32->is_attached && display_win32->hasWglEXTSwapControl) +#ifdef GDK_WIN32_ENABLE_EGL + else { - surface = gdk_gl_context_get_surface (context); + EGLSurface egl_surface; - /* 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); + surface = gdk_gl_context_get_surface (context); - if (do_frame_sync != context_win32->do_frame_sync) + if (context_win32->is_attached) + egl_surface = _gdk_win32_surface_get_egl_surface (surface, 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_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; } @@ -868,3 +1277,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)) + { + GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (surface->impl); + + 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 <epoxy/gl.h> #include <epoxy/wgl.h> +#ifdef GDK_WIN32_ENABLE_EGL +# include <epoxy/egl.h> +#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 d47d67bfdb..a7900d2035 100644 --- a/gdk/win32/gdksurface-win32.c +++ b/gdk/win32/gdksurface-win32.c @@ -750,6 +750,7 @@ gdk_win32_surface_destroy (GdkSurface *window, { GdkSurfaceImplWin32 *surface_impl = GDK_SURFACE_IMPL_WIN32 (window->impl); GSList *tmp; + GdkWin32Display *display = NULL; g_return_if_fail (GDK_IS_SURFACE (window)); @@ -766,6 +767,22 @@ gdk_win32_surface_destroy (GdkSurface *window, gdk_surface_set_transient_for (child, NULL); } +#ifdef GDK_WIN32_ENABLE_EGL + display = GDK_WIN32_DISPLAY (gdk_surface_get_display (window)); + + /* Get rid of any EGLSurfaces that we might have created */ + if (surface_impl->egl_surface != EGL_NO_SURFACE) + { + eglDestroySurface (display->egl_disp, surface_impl->egl_surface); + surface_impl->egl_surface = EGL_NO_SURFACE; + } + if (surface_impl->egl_dummy_surface != EGL_NO_SURFACE) + { + eglDestroySurface (display->egl_disp, surface_impl->egl_dummy_surface); + surface_impl->egl_dummy_surface = EGL_NO_SURFACE; + } +#endif + /* Remove ourself from our transient owner */ if (surface_impl->transient_owner != NULL) { @@ -1349,14 +1366,15 @@ gdk_win32_surface_move_resize (GdkSurface *window, } else { + _gdk_win32_surface_invalidate_egl_framebuffer (window); if (with_move) - { - gdk_win32_surface_move_resize_internal (window, x, y, width, height); - } + { + gdk_win32_surface_move_resize_internal (window, x, y, width, height); + } else - { - gdk_win32_surface_resize (window, width, height); - } + { + gdk_win32_surface_resize (window, width, height); + } } out: @@ -4182,6 +4200,9 @@ gdk_win32_surface_end_move_resize_drag (GdkSurface *window) { GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl); 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; @@ -4711,6 +4732,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 @@ -5388,3 +5411,34 @@ gdk_win32_surface_get_handle (GdkSurface *window) return GDK_SURFACE_HWND (window); } + +#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)); + GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (surface->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/gdksurface-win32.h b/gdk/win32/gdksurface-win32.h index bdfddeeb24..4c87e8a5df 100644 --- a/gdk/win32/gdksurface-win32.h +++ b/gdk/win32/gdksurface-win32.h @@ -32,6 +32,10 @@ #include <windows.h> +#ifdef GDK_WIN32_ENABLE_EGL +# include <epoxy/egl.h> +#endif + G_BEGIN_DECLS /* Window implementation for Win32 @@ -353,6 +357,12 @@ struct _GdkSurfaceImplWin32 gint surface_scale; gint unscaled_width; gint unscaled_height; + +#ifdef GDK_WIN32_ENABLE_EGL + EGLSurface egl_surface; + EGLSurface egl_dummy_surface; + guint egl_force_redraw_all : 1; +#endif }; struct _GdkSurfaceImplWin32Class @@ -383,6 +393,11 @@ void _gdk_win32_update_layered_window_from_cache (GdkSurface *window, gboolean do_resize, gboolean do_paint); +#ifdef GDK_WIN32_ENABLE_EGL +EGLSurface _gdk_win32_surface_get_egl_surface (GdkSurface *surface, + EGLConfig config, + gboolean is_dummy); +#endif G_END_DECLS |