diff options
Diffstat (limited to 'gdk')
-rw-r--r-- | gdk/win32/Makefile.am | 5 | ||||
-rw-r--r-- | gdk/win32/gdkdisplay-win32.c | 14 | ||||
-rw-r--r-- | gdk/win32/gdkdisplay-win32.h | 47 | ||||
-rw-r--r-- | gdk/win32/gdkglcontext-win32.c | 655 | ||||
-rw-r--r-- | gdk/win32/gdkglcontext-win32.h | 84 | ||||
-rw-r--r-- | gdk/win32/gdkwin32.h | 1 | ||||
-rw-r--r-- | gdk/win32/gdkwin32glcontext.h | 49 | ||||
-rw-r--r-- | gdk/win32/gdkwindow-win32.c | 24 |
8 files changed, 861 insertions, 18 deletions
diff --git a/gdk/win32/Makefile.am b/gdk/win32/Makefile.am index 640a215b3e..9366867780 100644 --- a/gdk/win32/Makefile.am +++ b/gdk/win32/Makefile.am @@ -37,10 +37,13 @@ libgdk_win32_la_SOURCES = \ gdkdevice-wintab.c \ gdkdevice-wintab.h \ gdkdisplay-win32.c \ + gdkdisplay-win32.h \ gdkdisplaymanager-win32.c \ gdkdnd-win32.c \ gdkevents-win32.c \ gdkgeometry-win32.c \ + gdkglcontext-win32.c \ + gdkglcontext-win32.h \ gdkglobals-win32.c \ gdkinput.c \ gdkkeys-win32.c \ @@ -55,6 +58,7 @@ libgdk_win32_la_SOURCES = \ gdkwin32display.h \ gdkwin32displaymanager.h \ gdkwin32dnd.h \ + gdkwin32glcontext.h \ gdkwin32.h \ gdkwin32id.c \ gdkwin32keys.h \ @@ -74,6 +78,7 @@ libgdkwin32include_HEADERS = \ gdkwin32display.h \ gdkwin32displaymanager.h\ gdkwin32dnd.h \ + gdkwin32glcontext.h \ gdkwin32keys.h \ gdkwin32misc.h \ gdkwin32screen.h \ diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c index 97d0e3e0fb..b4f004dc07 100644 --- a/gdk/win32/gdkdisplay-win32.c +++ b/gdk/win32/gdkdisplay-win32.c @@ -19,7 +19,8 @@ #include "config.h" #include "gdk.h" #include "gdkprivate-win32.h" -#include "gdkdisplayprivate.h" +#include "gdkdisplay-win32.h" +#include "gdkglcontext-win32.h" #include "gdkwin32display.h" #include "gdkwin32screen.h" #include "gdkwin32window.h" @@ -216,16 +217,6 @@ _gdk_win32_display_open (const gchar *display_name) return _gdk_display; } -struct _GdkWin32Display -{ - GdkDisplay display; -}; - -struct _GdkWin32DisplayClass -{ - GdkDisplayClass display_class; -}; - G_DEFINE_TYPE (GdkWin32Display, gdk_win32_display, GDK_TYPE_DISPLAY) static const gchar * @@ -664,6 +655,7 @@ gdk_win32_display_class_init (GdkWin32DisplayClass *klass) display_class->convert_selection = _gdk_win32_display_convert_selection; display_class->text_property_to_utf8_list = _gdk_win32_display_text_property_to_utf8_list; display_class->utf8_to_string_target = _gdk_win32_display_utf8_to_string_target; + display_class->make_gl_context_current = _gdk_win32_display_make_gl_context_current; _gdk_win32_windowing_init (); } diff --git a/gdk/win32/gdkdisplay-win32.h b/gdk/win32/gdkdisplay-win32.h new file mode 100644 index 0000000000..a3e2ea1e66 --- /dev/null +++ b/gdk/win32/gdkdisplay-win32.h @@ -0,0 +1,47 @@ +/* + * gdkdisplay-win32.h + * + * Copyright 2014 Chun-wei Fan <fanc999@yahoo.com.tw> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "gdkdisplayprivate.h" + +#ifndef __GDK_DISPLAY__WIN32_H__ +#define __GDK_DISPLAY__WIN32_H__ + +struct _GdkWin32Display +{ + GdkDisplay display; + + /* WGL/OpenGL Items */ + guint have_wgl : 1; + guint gl_version; + HDC gl_hdc; + HWND gl_hwnd; + + guint hasWglARBCreateContext : 1; + guint hasWglARBPbuffer : 1; + guint hasWglARBRenderTexture : 1; + guint hasWglEXTSwapControl : 1; + guint hasWglOMLSyncControl : 1; +}; + +struct _GdkWin32DisplayClass +{ + GdkDisplayClass display_class; +}; + +#endif /* __GDK_DISPLAY__WIN32_H__ */ diff --git a/gdk/win32/gdkglcontext-win32.c b/gdk/win32/gdkglcontext-win32.c new file mode 100644 index 0000000000..7f61493c66 --- /dev/null +++ b/gdk/win32/gdkglcontext-win32.c @@ -0,0 +1,655 @@ +/* GDK - The GIMP Drawing Kit + * + * gdkglcontext-win32.c: Win32 specific OpenGL wrappers + * + * Copyright © 2014 Emmanuele Bassi + * Copyright © 2014 Alexander Larsson + * Copyright © 2014 Chun-wei Fan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include "gdkprivate-win32.h" +#include "gdkwindow-win32.h" +#include "gdkglcontext-win32.h" +#include "gdkdisplay-win32.h" + +#include "gdkwin32display.h" +#include "gdkwin32glcontext.h" +#include "gdkwin32misc.h" +#include "gdkwin32screen.h" +#include "gdkwin32window.h" + +#include "gdkglcontext.h" +#include "gdkwindow.h" +#include "gdkinternals.h" +#include "gdkintl.h" + +#include <cairo.h> +#include <epoxy/wgl.h> + +G_DEFINE_TYPE (GdkWin32GLContext, gdk_win32_gl_context, GDK_TYPE_GL_CONTEXT) + +static void +_gdk_win32_gl_context_dispose (GObject *gobject) +{ + GdkGLContext *context = GDK_GL_CONTEXT (gobject); + GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (gobject); + GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)); + + if (context_win32->hglrc != NULL) + { + 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); + } + + G_OBJECT_CLASS (gdk_win32_gl_context_parent_class)->dispose (gobject); +} + +static void +gdk_win32_gl_context_class_init (GdkWin32GLContextClass *klass) +{ + GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + context_class->end_frame = _gdk_win32_gl_context_end_frame; + context_class->upload_texture = _gdk_win32_gl_context_upload_texture; + + gobject_class->dispose = _gdk_win32_gl_context_dispose; +} + +static void +gdk_win32_gl_context_init (GdkWin32GLContext *self) +{ +} + +static void +gdk_gl_blit_region (GdkWindow *window, cairo_region_t *region) +{ + int n_rects, i; + int scale = gdk_window_get_scale_factor (window); + int wh = gdk_window_get_height (window); + cairo_rectangle_int_t rect; + + n_rects = cairo_region_num_rectangles (region); + for (i = 0; i < n_rects; i++) + { + cairo_region_get_rectangle (region, i, &rect); + glScissor (rect.x * scale, (wh - rect.y - rect.height) * scale, rect.width * scale, rect.height * scale); + glBlitFramebuffer (rect.x * scale, (wh - rect.y - rect.height) * scale, (rect.x + rect.width) * scale, (wh - rect.y) * scale, + rect.x * scale, (wh - rect.y - rect.height) * scale, (rect.x + rect.width) * scale, (wh - rect.y) * scale, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + } +} + +void +_gdk_win32_gl_context_end_frame (GdkGLContext *context, + cairo_region_t *painted, + cairo_region_t *damage) +{ + GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (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) + { + guint32 end_frame_counter = 0; + + if (context_win32->do_frame_sync) + { + glFinish (); + + if (can_wait) + { + gint64 ust, msc, sbc; + + wglGetSyncValuesOML (context_win32->gl_hdc, &ust, &msc, &sbc); + wglWaitForMscOML (context_win32->gl_hdc, + 0, + 2, + (msc + 1) % 2, + &ust, &msc, &sbc); + } + } + } + + 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); +} + +void +_gdk_win32_window_invalidate_for_new_frame (GdkWindow *window, + cairo_region_t *update_area) +{ + cairo_rectangle_int_t window_rect; + unsigned int buffer_age; + gboolean invalidate_all = FALSE; + GdkWin32GLContext *context_win32; + cairo_rectangle_int_t whole_window = { 0, 0, gdk_window_get_width (window), gdk_window_get_height (window) }; + + /* Minimal update is ok if we're not drawing with gl */ + if (window->gl_paint_context == NULL) + return; + + context_win32 = GDK_WIN32_GL_CONTEXT (window->gl_paint_context); + context_win32->do_blit_swap = FALSE; + + if (gdk_gl_context_has_framebuffer_blit (window->gl_paint_context) && + cairo_region_contains_rectangle (update_area, &whole_window) != CAIRO_REGION_OVERLAP_IN) + { + context_win32->do_blit_swap = TRUE; + } + else + invalidate_all = TRUE; + + if (invalidate_all) + { + window_rect.x = 0; + window_rect.y = 0; + window_rect.width = gdk_window_get_width (window); + window_rect.height = gdk_window_get_height (window); + + /* If nothing else is known, repaint everything so that the back + buffer is fully up-to-date for the swapbuffer */ + cairo_region_union_rectangle (update_area, &window_rect); + } +} + +void +_gdk_win32_gl_context_upload_texture (GdkGLContext *context, + cairo_surface_t *image_surface, + int width, + int height, + guint texture_target) +{ + g_return_if_fail (GDK_WIN32_IS_GL_CONTEXT (context)); + + glPixelStorei (GL_UNPACK_ALIGNMENT, 4); + glPixelStorei (GL_UNPACK_ROW_LENGTH, cairo_image_surface_get_stride (image_surface)/4); + glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, + cairo_image_surface_get_data (image_surface)); + glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); +} + +typedef struct +{ + ATOM wc_atom; + HWND hwnd; + HDC hdc; + HGLRC hglrc; + gboolean inited; +} GdkWGLDummy; + +static void +_destroy_dummy_gl_context (GdkWGLDummy dummy) +{ + if (dummy.hglrc != NULL) + { + if (wglGetCurrentContext () == dummy.hglrc) + wglMakeCurrent (NULL, NULL); + wglDeleteContext (dummy.hglrc); + dummy.hglrc = NULL; + } + if (dummy.hdc != NULL) + { + DeleteDC (dummy.hdc); + dummy.hdc = NULL; + } + if (dummy.hwnd != NULL) + { + DestroyWindow (dummy.hwnd); + dummy.hwnd = NULL; + } + if (dummy.wc_atom != 0) + { + UnregisterClass (MAKEINTATOM (dummy.wc_atom), GetModuleHandle (NULL)); + dummy.wc_atom = 0; + } + dummy.inited = FALSE; +} + +/* Yup, we need to create a dummy window for the dummy WGL context */ +static void +_get_dummy_window_hwnd (GdkWGLDummy *dummy) +{ + WNDCLASSEX dummy_wc; + HWND dummy_hwnd; + + memset (&dummy_wc, 0, sizeof (WNDCLASSEX)); + + dummy_wc.cbSize = sizeof( WNDCLASSEX ); + dummy_wc.style = CS_OWNDC; + dummy_wc.lpfnWndProc = (WNDPROC) DefWindowProc; + dummy_wc.cbClsExtra = 0; + dummy_wc.cbWndExtra = 0; + dummy_wc.hInstance = GetModuleHandle( NULL ); + dummy_wc.hIcon = 0; + dummy_wc.hCursor = NULL; + dummy_wc.hbrBackground = 0; + dummy_wc.lpszMenuName = 0; + dummy_wc.lpszClassName = "dummy"; + dummy_wc.hIconSm = 0; + + dummy->wc_atom = RegisterClassEx (&dummy_wc); + + dummy->hwnd = + CreateWindowEx (WS_EX_APPWINDOW, + MAKEINTATOM (dummy->wc_atom), + "", + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + 0, + 0, + 0, + 0, + NULL, + NULL, + GetModuleHandle (NULL), + NULL); +} + +static gint +_get_wgl_pfd (HDC hdc, + const gboolean need_alpha_bits, + PIXELFORMATDESCRIPTOR *pfd) +{ + gint configs; + gint i; + gint best_pf = 0; + gboolean alpha_check; + + pfd->nSize = sizeof (PIXELFORMATDESCRIPTOR); + pfd->nVersion = 1; + pfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; + pfd->iPixelType = PFD_TYPE_RGBA; + pfd->cColorBits = GetDeviceCaps (hdc, BITSPIXEL); + pfd->cAlphaBits = 8; + pfd->dwLayerMask = PFD_MAIN_PLANE; + + best_pf = ChoosePixelFormat (hdc, pfd); + + if (best_pf == 0) + /* give another chance if need_alpha_bits is FALSE, + * meaning we prefer to have an alpha channel anyways + */ + if (!need_alpha_bits) + { + pfd->cAlphaBits = 0; + best_pf = ChoosePixelFormat (hdc, pfd); + } + + return best_pf; +} + +/* in WGL, for many OpenGL items, we need a dummy WGL context, so create + * one and cache it for later use + */ +static gint +_gdk_init_dummy_context (GdkWGLDummy *dummy, + const gboolean need_alpha_bits) +{ + PIXELFORMATDESCRIPTOR pfd; + gboolean set_pixel_format_result = FALSE; + gint best_idx = 0; + + _get_dummy_window_hwnd (dummy); + + dummy->hdc = GetDC (dummy->hwnd); + memset (&pfd, 0, sizeof (PIXELFORMATDESCRIPTOR)); + + best_idx = _get_wgl_pfd (dummy->hdc, need_alpha_bits, &pfd); + + if (best_idx != 0) + set_pixel_format_result = SetPixelFormat (dummy->hdc, + best_idx, + &pfd); + + if (best_idx == 0 || !set_pixel_format_result) + return 0; + + dummy->hglrc = wglCreateContext (dummy->hdc); + if (dummy->hglrc == NULL) + return 0; + + dummy->inited = TRUE; + + return best_idx; +} + +gboolean +_gdk_win32_display_init_gl (GdkDisplay *display, + const gboolean need_alpha_bits) +{ + GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display); + gint glMajMinVersion; + GdkWindowImplWin32 *impl; + gint best_idx = 0; + GdkWGLDummy dummy; + + if (display_win32->have_wgl) + return TRUE; + + 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, need_alpha_bits); + + 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"); + + GDK_NOTE (OPENGL, + g_print ("WGL API version %d.%d found\n" + " - Vendor: %s\n" + " - Checked extensions:\n" + "\t* WGL_ARB_create_context: %s\n" + "\t* WGL_EXT_swap_control: %s\n" + "\t* WGL_OML_sync_control: %s\n", + display_win32->gl_version / 10, + display_win32->gl_version % 10, + glGetString (GL_VENDOR), + display_win32->hasWglARBCreateContext ? "yes" : "no", + display_win32->hasWglEXTSwapControl ? "yes" : "no", + display_win32->hasWglOMLSyncControl ? "yes" : "no")); + + wglMakeCurrent (NULL, NULL); + _destroy_dummy_gl_context (dummy); + + return TRUE; +} + +static HGLRC +_create_gl_context (HDC hdc, GdkGLContext *share, GdkGLProfile profile) +{ + HGLRC hglrc; + + /* we need a legacy context first, for all cases */ + hglrc = wglCreateContext (hdc); + + /* Create a WGL 3.2 context, the legacy context *is* needed here */ + if (profile == GDK_GL_PROFILE_3_2_CORE) + { + HGLRC hglrc_32; + GdkWin32GLContext *context_win32; + + gint attribs[] = { + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, + WGL_CONTEXT_MINOR_VERSION_ARB, 2, + 0 + }; + + if (!wglMakeCurrent (hdc, hglrc)) + return NULL; + + if (share != NULL) + context_win32 = GDK_WIN32_GL_CONTEXT (share); + + hglrc_32 = wglCreateContextAttribsARB (hdc, + share != NULL ? context_win32->hglrc : NULL, + attribs); + + wglMakeCurrent (NULL, NULL); + wglDeleteContext (hglrc); + return hglrc_32; + } + else + { + /* for legacy WGL, we can't share lists during context creation, + * so do so immediately afterwards + */ + if (share != NULL) + { + HGLRC hglrc_shared = GDK_WIN32_GL_CONTEXT (share)->hglrc; + wglShareLists (hglrc_shared, hglrc); + } + return hglrc; + } +} + +static gboolean +_set_pixformat_for_hdc (HDC hdc, + gint *best_idx, + const gboolean need_alpha_bits) +{ + PIXELFORMATDESCRIPTOR pfd; + gboolean set_pixel_format_result = FALSE; + + /* one is only allowed to call SetPixelFormat(), and so ChoosePixelFormat() + * one single time per window HDC + */ + *best_idx = _get_wgl_pfd (hdc, need_alpha_bits, &pfd); + if (*best_idx != 0) + set_pixel_format_result = SetPixelFormat (hdc, *best_idx, &pfd); + + /* ChoosePixelFormat() or SetPixelFormat() failed, bail out */ + if (*best_idx == 0 || !set_pixel_format_result) + return FALSE; + return TRUE; +} + +GdkGLContext * +_gdk_win32_window_create_gl_context (GdkWindow *window, + gboolean attached, + GdkGLProfile profile, + GdkGLContext *share, + GError **error) +{ + GdkDisplay *display = gdk_window_get_display (window); + GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_window_get_display (window)); + GdkWin32GLContext *context = NULL; + GdkVisual *visual = gdk_window_get_visual (window); + + /* XXX: gdk_screen_get_rgba_visual() is not implemented on Windows, so + * need_alpha_bits will always be FALSE for now. + * + * Please see bug https://bugzilla.gnome.org/show_bug.cgi?id=727316 + */ + gboolean need_alpha_bits = (visual == gdk_screen_get_rgba_visual (gdk_display_get_default_screen (display))); + + /* Real GL Context and Window items */ + WNDCLASSEX wc; + ATOM wc_atom; + HWND hwnd; + HDC hdc; + HGLRC hglrc; + gint pixel_format; + + if (!_gdk_win32_display_init_gl (display, need_alpha_bits)) + { + g_set_error_literal (error, GDK_GL_ERROR, + GDK_GL_ERROR_NOT_AVAILABLE, + _("No GL implementation is available")); + return NULL; + } + + if (profile == GDK_GL_PROFILE_3_2_CORE && + !display_win32->hasWglARBCreateContext) + { + g_set_error_literal (error, GDK_GL_ERROR, + GDK_GL_ERROR_UNSUPPORTED_PROFILE, + _("The WGL_ARB_create_context extension " + "needed to create 3.2 core profiles is not " + "available")); + return NULL; + } + + hwnd = GDK_WINDOW_HWND (window); + hdc = GetDC (hwnd); + + if (!_set_pixformat_for_hdc (hdc, &pixel_format, need_alpha_bits)) + { + g_set_error_literal (error, GDK_GL_ERROR, + GDK_GL_ERROR_UNSUPPORTED_FORMAT, + _("No available configurations for the given pixel format")); + return NULL; + } + + if (profile != GDK_GL_PROFILE_3_2_CORE) + profile = GDK_GL_PROFILE_LEGACY; + + hglrc = _create_gl_context (hdc, share, profile); + + + if (hglrc == NULL) + { + g_set_error_literal (error, GDK_GL_ERROR, + GDK_GL_ERROR_NOT_AVAILABLE, + _("Unable to create a GL context")); + return NULL; + } + + display_win32->gl_hdc = hdc; + display_win32->gl_hwnd = hwnd; + + GDK_NOTE (OPENGL, + g_print ("Created WGL context[%p], pixel_format=%d\n", + hglrc, + pixel_format)); + + context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT, + "display", display, + "window", window, + "profile", profile, + "shared-context", share, + NULL); + + context->hglrc = hglrc; + context->gl_hdc = hdc; + context->is_attached = attached; + + return GDK_GL_CONTEXT (context); +} + +gboolean +_gdk_win32_display_make_gl_context_current (GdkDisplay *display, + GdkGLContext *context) +{ + GdkWin32GLContext *context_win32; + GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display); + GdkWindow *window; + GdkScreen *screen; + + gboolean do_frame_sync = FALSE; + + if (context == NULL) + { + wglMakeCurrent(NULL, NULL); + return TRUE; + } + + context_win32 = GDK_WIN32_GL_CONTEXT (context); + + if (!wglMakeCurrent (display_win32->gl_hdc, context_win32->hglrc)) + { + GDK_NOTE (OPENGL, + g_print ("Making WGL context current failed\n")); + return FALSE; + } + + context_win32->gl_hdc = display_win32->gl_hdc; + + if (context_win32->is_attached && display_win32->hasWglEXTSwapControl) + { + 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); + + /* XXX: gdk_screen_is_composited () is always FALSE on Windows at the moment */ + 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); + } + } + + return TRUE; +} + +/** + * gdk_win32_display_get_wgl_version: + * @display: a #GdkDisplay + * @major: (out): return location for the WGL major version + * @minor: (out): return location for the WGL minor version + * + * Retrieves the version of the WGL implementation. + * + * Returns: %TRUE if WGL is available + * + * Since: 3.16 + */ +gboolean +gdk_win32_display_get_wgl_version (GdkDisplay *display, + gint *major, + gint *minor) +{ + 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)) + return FALSE; + + if (major != NULL) + *major = GDK_WIN32_DISPLAY (display)->gl_version / 10; + if (minor != NULL) + *minor = GDK_WIN32_DISPLAY (display)->gl_version % 10; + + return TRUE; +} diff --git a/gdk/win32/gdkglcontext-win32.h b/gdk/win32/gdkglcontext-win32.h new file mode 100644 index 0000000000..7ee9b5e4f3 --- /dev/null +++ b/gdk/win32/gdkglcontext-win32.h @@ -0,0 +1,84 @@ +/* GDK - The GIMP Drawing Kit + * + * gdkglcontext-win32.h: Private Win32 specific OpenGL wrappers + * + * Copyright © 2014 Chun-wei Fan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GDK_WIN32_GL_CONTEXT__ +#define __GDK_WIN32_GL_CONTEXT__ + +#include <epoxy/gl.h> +#include <epoxy/wgl.h> + +#include "gdkglcontextprivate.h" +#include "gdkdisplayprivate.h" +#include "gdkvisual.h" +#include "gdkwindow.h" +#include "gdkinternals.h" +#include "gdkmain.h" + +G_BEGIN_DECLS + +struct _GdkWin32GLContext +{ + GdkGLContext parent_instance; + + /* WGL Context Items */ + HGLRC hglrc; + HDC gl_hdc; + + /* other items */ + guint is_attached : 1; + guint do_frame_sync : 1; + guint do_blit_swap : 1; +}; + +struct _GdkWin32GLContextClass +{ + GdkGLContextClass parent_class; +}; + +GdkGLContext * +_gdk_win32_window_create_gl_context (GdkWindow *window, + gboolean attached, + GdkGLProfile profile, + GdkGLContext *share, + GError **error); + +void +_gdk_win32_window_invalidate_for_new_frame (GdkWindow *window, + cairo_region_t *update_area); + +void +_gdk_win32_gl_context_end_frame (GdkGLContext *context, + cairo_region_t *painted, + cairo_region_t *damage); + +void +_gdk_win32_gl_context_upload_texture (GdkGLContext *context, + cairo_surface_t *image_surface, + int width, + int height, + guint texture_target); + +gboolean +_gdk_win32_display_make_gl_context_current (GdkDisplay *display, + GdkGLContext *context); + +G_END_DECLS + +#endif /* __GDK_WIN32_GL_CONTEXT__ */ diff --git a/gdk/win32/gdkwin32.h b/gdk/win32/gdkwin32.h index 5256392a69..4550dc72fa 100644 --- a/gdk/win32/gdkwin32.h +++ b/gdk/win32/gdkwin32.h @@ -35,6 +35,7 @@ #include <gdk/win32/gdkwin32screen.h> #include <gdk/win32/gdkwin32window.h> #include <gdk/win32/gdkwin32misc.h> +#include <gdk/win32/gdkwin32glcontext.h> #undef __GDKWIN32_H_INSIDE__ diff --git a/gdk/win32/gdkwin32glcontext.h b/gdk/win32/gdkwin32glcontext.h new file mode 100644 index 0000000000..fc6e94c798 --- /dev/null +++ b/gdk/win32/gdkwin32glcontext.h @@ -0,0 +1,49 @@ +/* GDK - The GIMP Drawing Kit + * + * gdkglcontext-win32.c: Win32 specific OpenGL wrappers + * + * Copyright © 2014 Chun-wei Fan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GDK_WIN32_GL_CONTEXT_H__ +#define __GDK_WIN32_GL_CONTEXT_H__ + +#if !defined (__GDKWIN32_H_INSIDE__) && !defined (GDK_COMPILATION) +#error "Only <gdk/gdkwin32.h> can be included directly." +#endif + +#include <gdk/gdk.h> + +G_BEGIN_DECLS + +#define GDK_TYPE_WIN32_GL_CONTEXT (gdk_win32_gl_context_get_type ()) +#define GDK_WIN32_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_WIN32_GL_CONTEXT, GdkWin32GLContext)) +#define GDK_WIN32_IS_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_WIN32_GL_CONTEXT)) + +typedef struct _GdkWin32GLContext GdkWin32GLContext; +typedef struct _GdkWin32GLContextClass GdkWin32GLContextClass; + +GDK_AVAILABLE_IN_3_16 +GType gdk_win32_gl_context_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_3_16 +gboolean gdk_win32_display_get_wgl_version (GdkDisplay *display, + gint *major, + gint *minor); + +G_END_DECLS + +#endif /* __GDK_WIN32_GL_CONTEXT_H__ */ diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index 7b4bd7945b..3e568a4a99 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -38,6 +38,7 @@ #include "gdkdisplayprivate.h" #include "gdkvisualprivate.h" #include "gdkwin32window.h" +#include "gdkglcontext-win32.h" #include <cairo-win32.h> @@ -336,13 +337,15 @@ RegisterGdkClass (GdkWindowType wtype, GdkWindowTypeHint wtype_hint) switch (wtype) { case GDK_WINDOW_TOPLEVEL: + /* MSDN: CS_OWNDC is needed for OpenGL contexts */ + wcl.style |= CS_OWNDC; if (0 == klassTOPLEVEL) - { - wcl.lpszClassName = L"gdkWindowToplevel"; - - ONCE_PER_CLASS (); - klassTOPLEVEL = RegisterClassExW (&wcl); - } + { + wcl.lpszClassName = L"gdkWindowToplevel"; + + ONCE_PER_CLASS (); + klassTOPLEVEL = RegisterClassExW (&wcl); + } klass = klassTOPLEVEL; break; @@ -351,6 +354,10 @@ RegisterGdkClass (GdkWindowType wtype, GdkWindowTypeHint wtype_hint) { wcl.lpszClassName = L"gdkWindowChild"; + /* XXX: Find out whether GL Widgets are done for GDK_WINDOW_CHILD + * MSDN says CS_PARENTDC should not be used for GL Context + * creation + */ wcl.style |= CS_PARENTDC; /* MSDN: ... enhances system performance. */ ONCE_PER_CLASS (); klassCHILD = RegisterClassExW (&wcl); @@ -524,8 +531,9 @@ _gdk_win32_display_create_window_impl (GdkDisplay *display, } else { + /* MSDN: We need WS_CLIPCHILDREN and WS_CLIPSIBLINGS for GL Context Creation */ if (window->window_type == GDK_WINDOW_TOPLEVEL) - dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN; + dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; else dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN; @@ -3440,6 +3448,8 @@ gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass) impl_class->get_property = _gdk_win32_window_get_property; impl_class->change_property = _gdk_win32_window_change_property; impl_class->delete_property = _gdk_win32_window_delete_property; + impl_class->create_gl_context = _gdk_win32_window_create_gl_context; + impl_class->invalidate_for_new_frame = _gdk_win32_window_invalidate_for_new_frame; } HGDIOBJ |