Add OpenGL Support for the GDK Windows Backend

This adds support for OpenGL to the GDK Windows backend using the WGL API
calls, which enables programs that uses the GTK+ GLArea widgets to work on
Windows as well.

This also adds a simple utility function to query for the version of OpenGL
that is supported by the Windows system, like the one provided by the X11
backend.

Many thanks to Alex (and Emmanuele, who started the OpenGL integration in
GTK+) who offered advice and help along the way, as well as the X11 and
Wayland backend for this work to refer to and to model upon.

https://bugzilla.gnome.org/show_bug.cgi?id=740795
This commit is contained in:
Chun-wei Fan 2014-12-17 12:32:04 +08:00
parent 9fd9f61b00
commit 536fa88cd8
8 changed files with 861 additions and 18 deletions

View File

@ -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 \

View File

@ -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 ();
}

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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__

View File

@ -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__ */

View File

@ -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