/* 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 .
*/
#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
#include
#ifdef GDK_WIN32_ENABLE_EGL
# include
#endif
struct _GdkWin32GLContext
{
GdkGLContext parent_instance;
HDC gl_hdc;
guint need_alpha_bits : 1;
guint is_attached : 1;
guint do_frame_sync : 1;
guint do_blit_swap : 1;
};
struct _GdkWin32GLContextClass
{
GdkGLContextClass parent_class;
};
G_DEFINE_TYPE (GdkWin32GLContext, gdk_win32_gl_context, GDK_TYPE_GL_CONTEXT)
static void
gdk_win32_gl_context_cleanup (GdkGLContext *context)
{
GdkWindow *window = gdk_gl_context_get_window (context);
if (window != NULL)
{
GdkWindowImplWin32 *impl = NULL;
ReleaseDC (GDK_WINDOW_HWND (window), GDK_WIN32_GL_CONTEXT(context)->gl_hdc);
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
if (impl->suppress_layered > 0)
impl->suppress_layered--;
/* If we don't have any window that forces layered windows off,
* trigger update_style_bits() to enable layered windows again
*/
if (impl->suppress_layered == 0)
_gdk_win32_window_update_style_bits (window);
}
}
static void
gdk_gl_blit_region (GdkWindow *window,
cairo_region_t *region,
gboolean use_intel_workaround)
{
int n_rects, i, j;
int scale = gdk_window_get_scale_factor (window);
int wh = gdk_window_get_height (window);
cairo_rectangle_int_t rect;
int retries = 0;
if (use_intel_workaround)
retries = 1;
n_rects = cairo_region_num_rectangles (region);
for (i = 0; i <= retries; i ++)
{
for (j = 0; j < n_rects; j++)
{
cairo_region_get_rectangle (region, j, &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);
}
if (retries > 0 && i < retries)
glFlush ();
}
}
/* Section on WGL usage */
struct _GdkWin32GLContextWGL
{
GdkWin32GLContext parent_instance;
HGLRC wgl_context;
};
typedef struct _GdkWin32GLContextClass GdkWin32GLContextWGLClass;
typedef struct _GdkWin32GLContextWGL GdkWin32GLContextWGL;
G_DEFINE_TYPE (GdkWin32GLContextWGL, gdk_win32_gl_context_wgl, GDK_TYPE_WIN32_GL_CONTEXT)
#define GDK_TYPE_WIN32_GL_CONTEXT_WGL (gdk_win32_gl_context_wgl_get_type())
#define GDK_WIN32_GL_CONTEXT_WGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_WIN32_GL_CONTEXT_WGL, GdkWin32GLContextWGL))
#define GDK_IS_WIN32_GL_CONTEXT_WGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_WIN32_GL_CONTEXT_WGL))
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)
{
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;
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
gdk_init_dummy_context (GdkWGLDummy *dummy,
const gboolean need_alpha_bits);
#define PIXEL_ATTRIBUTES 19
static gint
get_wgl_pfd (HDC hdc,
const gboolean need_alpha_bits,
PIXELFORMATDESCRIPTOR *pfd,
GdkWin32Display *display)
{
gint best_pf = 0;
pfd->nSize = sizeof (PIXELFORMATDESCRIPTOR);
if (display != NULL && display->hasWglARBPixelFormat)
{
GdkWGLDummy dummy;
UINT num_formats;
gint colorbits = GetDeviceCaps (hdc, BITSPIXEL);
guint extra_fields = 1;
gint i = 0;
int pixelAttribs[PIXEL_ATTRIBUTES];
int alpha_idx = 0;
/* Save up the HDC and HGLRC that we are currently using, to restore back to it when we are done here */
HDC hdc_current = wglGetCurrentDC ();
HGLRC hglrc_current = wglGetCurrentContext ();
if (display->hasWglARBmultisample)
{
/* 2 pairs of values needed for multisampling/AA support */
extra_fields += 2 * 2;
}
/* Update PIXEL_ATTRIBUTES above if any groups are added here! */
/* one group contains a value pair for both pixelAttribs and pixelAttribsNoAlpha */
pixelAttribs[i] = WGL_DRAW_TO_WINDOW_ARB;
pixelAttribs[i++] = GL_TRUE;
pixelAttribs[i++] = WGL_SUPPORT_OPENGL_ARB;
pixelAttribs[i++] = GL_TRUE;
pixelAttribs[i++] = WGL_DOUBLE_BUFFER_ARB;
pixelAttribs[i++] = GL_TRUE;
pixelAttribs[i++] = WGL_ACCELERATION_ARB;
pixelAttribs[i++] = WGL_FULL_ACCELERATION_ARB;
pixelAttribs[i++] = WGL_PIXEL_TYPE_ARB;
pixelAttribs[i++] = WGL_TYPE_RGBA_ARB;
pixelAttribs[i++] = WGL_COLOR_BITS_ARB;
pixelAttribs[i++] = colorbits;
/* end of "Update PIXEL_ATTRIBUTES above if any groups are added here!" */
if (display->hasWglARBmultisample)
{
pixelAttribs[i++] = WGL_SAMPLE_BUFFERS_ARB;
pixelAttribs[i++] = 1;
pixelAttribs[i++] = WGL_SAMPLES_ARB;
pixelAttribs[i++] = 8;
}
pixelAttribs[i++] = WGL_ALPHA_BITS_ARB;
/* track the spot where the alpha bits are, so that we can clear it if needed */
alpha_idx = i;
pixelAttribs[i++] = 8;
pixelAttribs[i++] = 0; /* end of pixelAttribs */
memset (&dummy, 0, sizeof (GdkWGLDummy));
/* acquire and cache dummy Window (HWND & HDC) and
* dummy GL Context, we need it for wglChoosePixelFormatARB()
*/
best_pf = gdk_init_dummy_context (&dummy, need_alpha_bits);
if (best_pf == 0 || !wglMakeCurrent (dummy.hdc, dummy.hglrc))
{
wglMakeCurrent (hdc_current, hglrc_current);
return 0;
}
wglChoosePixelFormatARB (hdc,
pixelAttribs,
NULL,
1,
&best_pf,
&num_formats);
if (best_pf == 0)
{
if (!need_alpha_bits)
{
pixelAttribs[alpha_idx] = 0;
pixelAttribs[alpha_idx + 1] = 0;
/* give another chance if need_alpha_bits is FALSE,
* meaning we prefer to have an alpha channel anyways
*/
wglChoosePixelFormatARB (hdc,
pixelAttribs,
NULL,
1,
&best_pf,
&num_formats);
}
}
/* Go back to the HDC that we were using, since we are done with the dummy HDC and GL Context */
wglMakeCurrent (hdc_current, hglrc_current);
destroy_dummy_gl_context (dummy);
}
else
{
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, NULL);
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;
}
static void
gdk_win32_gl_context_dispose_wgl (GObject *gobject)
{
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (context);
if (context_wgl->wgl_context != NULL)
{
GdkWindow *window = gdk_gl_context_get_window (context);
if (wglGetCurrentContext () == context_wgl->wgl_context)
wglMakeCurrent (NULL, NULL);
GDK_NOTE (OPENGL, g_print ("Destroying WGL context\n"));
wglDeleteContext (context_wgl->wgl_context);
context_wgl->wgl_context = NULL;
gdk_win32_gl_context_cleanup (context);
}
G_OBJECT_CLASS (gdk_win32_gl_context_parent_class)->dispose (gobject);
}
static void
gdk_win32_gl_context_end_frame_wgl (GdkGLContext *context,
cairo_region_t *painted,
cairo_region_t *damage)
{
GdkWin32Display *display_win32 = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)));
GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
gdk_gl_context_make_current (context);
if (context_win32->do_frame_sync)
{
glFinish ();
if (display_win32->hasWglOMLSyncControl)
{
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)
{
GdkWindow *window = gdk_gl_context_get_window (context);
glDrawBuffer(GL_FRONT);
glReadBuffer(GL_BACK);
gdk_gl_blit_region (window, painted, display_win32->needIntelGLWorkaround);
glDrawBuffer(GL_BACK);
glFlush();
if (gdk_gl_context_has_frame_terminator (context))
glFrameTerminatorGREMEDY ();
}
else
SwapBuffers (context_win32->gl_hdc);
}
/*
* We need to check whether the OpenGL driver is capable of delvering
* what we need to use in GdkGLContext. This function in the future
* will also check for blacklisted drivers, if needed. If things fail
* here, we can try falling back to OpenGL/ES (libANGLE) if that is enabled.
*/
static gboolean
gdk_win32_gl_context_wgl_check_capabilities (GdkWin32Display *display_win32,
GdkWGLDummy dummy)
{
if (!wglMakeCurrent (dummy.hdc, dummy.hglrc))
return FALSE;
display_win32->gl_version = epoxy_gl_version ();
/* We must have OpenGL/WGL 2.0 or later, or have the GL_ARB_shader_objects extension */
if (display_win32->gl_version < 20 && !epoxy_has_gl_extension ("GL_ARB_shader_objects"))
return FALSE;
return TRUE;
}
static void
gdk_win32_display_init_wgl (GdkWin32Display *display_win32,
const gboolean need_alpha_bits)
{
/* acquire and cache dummy Window (HWND & HDC) and
* dummy GL Context, it is used to query functions
* and used for other stuff as well
*/
GdkWGLDummy dummy;
gint best_idx = 0;
gboolean proceed = TRUE;
memset (&dummy, 0, sizeof (GdkWGLDummy));
best_idx = gdk_init_dummy_context (&dummy, need_alpha_bits);
if (best_idx != 0)
proceed = gdk_win32_gl_context_wgl_check_capabilities (display_win32, dummy);
if (best_idx != 0 && proceed)
{
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->needIntelGLWorkaround =
(g_ascii_strcasecmp (glGetString (GL_VENDOR), "intel") == 0);
GDK_NOTE (OPENGL,
g_print ("WGL API version %d.%d found\n"
" - Vendor: %s\n"
" - Intel OpenGL workaround: %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->needIntelGLWorkaround ? "yes" : "no",
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"));
display_win32->gl_type = GDK_WIN32_GL_WGL;
}
else
display_win32->gl_type = GDK_WIN32_GL_NONE;
/* clean up things if we indeed created our dummy WGL context */
if (best_idx != 0)
{
wglMakeCurrent (NULL, NULL);
destroy_dummy_gl_context (dummy);
}
}
/* Setup the legacy WGL context after creating it */
static gboolean
ensure_legacy_wgl_context (HDC hdc,
HGLRC hglrc_legacy,
GdkGLContext *share)
{
if (!wglMakeCurrent (hdc, hglrc_legacy))
return FALSE;
if (share != NULL)
{
GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (share);
return wglShareLists (hglrc_legacy, context_wgl->wgl_context);
}
return TRUE;
}
static HGLRC
create_wgl_context_with_attribs (HDC hdc,
HGLRC hglrc_base,
GdkGLContext *share,
int flags,
int major,
int minor,
gboolean *is_legacy)
{
HGLRC hglrc;
GdkWin32GLContextWGL *context_wgl;
/* if we have wglCreateContextAttribsARB(), create a
* context with the compatibility profile if a legacy
* context is requested, or when we go into fallback mode
*/
int profile = *is_legacy ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :
WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
int attribs[] = {
WGL_CONTEXT_PROFILE_MASK_ARB, profile,
WGL_CONTEXT_MAJOR_VERSION_ARB, *is_legacy ? 3 : major,
WGL_CONTEXT_MINOR_VERSION_ARB, *is_legacy ? 0 : minor,
WGL_CONTEXT_FLAGS_ARB, flags,
0
};
if (share != NULL)
context_wgl= GDK_WIN32_GL_CONTEXT_WGL (share);
hglrc = wglCreateContextAttribsARB (hdc,
share != NULL ? context_wgl->wgl_context : NULL,
attribs);
return hglrc;
}
static HGLRC
create_wgl_context (HDC hdc,
GdkGLContext *share,
int flags,
int major,
int minor,
gboolean *is_legacy,
gboolean hasWglARBCreateContext)
{
/* We need a legacy WGL context for *all* cases */
HGLRC hglrc_base = wglCreateContext (hdc);
gboolean success = TRUE;
/* Save up the HDC and HGLRC that we are currently using, to restore back to it when we are done here */
HDC hdc_current = wglGetCurrentDC ();
HGLRC hglrc_current = wglGetCurrentContext ();
/* if we have no wglCreateContextAttribsARB(), return the legacy context when all is set */
if (*is_legacy && !hasWglARBCreateContext)
{
if (ensure_legacy_wgl_context (hdc, hglrc_base, share))
{
wglMakeCurrent (hdc_current, hglrc_current);
return hglrc_base;
}
success = FALSE;
goto gl_fail;
}
else
{
HGLRC hglrc;
if (!wglMakeCurrent (hdc, hglrc_base))
{
success = FALSE;
goto gl_fail;
}
hglrc = create_wgl_context_with_attribs (hdc,
hglrc_base,
share,
flags,
major,
minor,
is_legacy);
/* return the legacy context we have if it could be setup properly, in case the 3.0+ context creation failed */
if (hglrc == NULL)
{
if (!(*is_legacy))
{
/* If we aren't using a legacy context in the beginning, try again with a compatibility profile 3.0 context */
hglrc = create_wgl_context_with_attribs (hdc,
hglrc_base,
share,
flags,
0, 0,
is_legacy);
*is_legacy = TRUE;
}
if (hglrc == NULL)
{
if (!ensure_legacy_wgl_context (hdc, hglrc_base, share))
success = FALSE;
}
if (success)
GDK_NOTE (OPENGL, g_print ("Using legacy context as fallback\n"));
}
gl_fail:
if (!success)
{
wglMakeCurrent (NULL, NULL);
wglDeleteContext (hglrc_base);
return NULL;
}
wglMakeCurrent (hdc_current, hglrc_current);
if (hglrc != NULL)
{
wglDeleteContext (hglrc_base);
return hglrc;
}
return hglrc_base;
}
}
static gboolean
set_pixformat_for_hdc (HDC hdc,
gint *best_idx,
const gboolean need_alpha_bits,
GdkWin32Display *display)
{
gboolean already_checked = TRUE;
*best_idx = GetPixelFormat (hdc);
/* one is only allowed to call SetPixelFormat(), and so ChoosePixelFormat()
* one single time per window HDC
*/
if (*best_idx == 0)
{
PIXELFORMATDESCRIPTOR pfd;
gboolean set_pixel_format_result = FALSE;
GDK_NOTE (OPENGL, g_print ("requesting pixel format...\n"));
already_checked = FALSE;
*best_idx = get_wgl_pfd (hdc, need_alpha_bits, &pfd, display);
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;
}
GDK_NOTE (OPENGL, g_print ("%s""requested and set pixel format: %d\n", already_checked ? "already " : "", *best_idx));
return TRUE;
}
static gboolean
gdk_win32_gl_context_realize_wgl (GdkGLContext *context,
GError **error)
{
GdkGLContext *share = gdk_gl_context_get_shared_context (context);
GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
GdkWindow *window = gdk_gl_context_get_window (context);
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_window_get_display (window));
/* These are the real WGL context items that we will want to use later */
gboolean debug_bit, compat_bit;
gboolean legacy_bit = FALSE;
HGLRC hglrc;
gint pixel_format;
/* request flags and specific versions for core (3.2+) WGL context */
gint flags = 0;
gint major = 0;
gint minor = 0;
/*
* A legacy context cannot be shared with core profile ones, this means we
* must stick to a legacy context if the shared context is a legacy context. We
* also use a legacy context if we use GDK_GL=legacy or if we do not have
* the WGL_ARB_create_context extension
*/
if ((_gdk_gl_flags & GDK_GL_LEGACY) != 0 ||
!display_win32->hasWglARBCreateContext ||
share != NULL && gdk_gl_context_is_legacy (share))
legacy_bit = TRUE;
/* say early enough that we are not using GLES, so that we acquire the correct versions */
gdk_gl_context_set_use_es (context, FALSE);
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 (!set_pixformat_for_hdc (context_win32->gl_hdc,
&pixel_format,
context_win32->need_alpha_bits,
display_win32))
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
_("No available configurations for the given pixel format"));
return FALSE;
}
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_wgl_context (context_win32->gl_hdc,
share,
flags,
major,
minor,
&legacy_bit,
display_win32->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));
GDK_WIN32_GL_CONTEXT_WGL (context)->wgl_context = hglrc;
/* OpenGL does not work with WS_EX_LAYERED enabled, so we need to
* disable WS_EX_LAYERED when we acquire a valid HGLRC
*/
impl->suppress_layered++;
/* if this is the first time a GL context is acquired for the window,
* disable layered windows by triggering update_style_bits()
*/
if (impl->suppress_layered == 1)
_gdk_win32_window_update_style_bits (window);
/* Ensure that any other context is created with a legacy bit set */
gdk_gl_context_set_is_legacy (context, legacy_bit);
return TRUE;
}
static gboolean
gdk_win32_display_make_wgl_context_current (GdkDisplay *display,
GdkGLContext *context)
{
GdkWin32GLContext *context_win32;
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
GdkWindow *window;
if (context == NULL)
{
wglMakeCurrent(NULL, NULL);
return TRUE;
}
context_win32 = GDK_WIN32_GL_CONTEXT (context);
window = gdk_gl_context_get_window (context);
if (!wglMakeCurrent (context_win32->gl_hdc,
GDK_WIN32_GL_CONTEXT_WGL (context)->wgl_context))
{
GDK_NOTE (OPENGL, g_print ("Making WGL context current failed\n"));
return FALSE;
}
if (context_win32->is_attached)
{
if (display_win32->hasWglEXTSwapControl)
{
/* If there is compositing there is no particular need to delay
* the swap when drawing on the offscreen, rendering to the screen
* happens later anyway, and its up to the compositor to sync that
* to the vblank. */
gboolean do_frame_sync = !gdk_screen_is_composited (gdk_window_get_screen (window));
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;
}
static void
gdk_win32_gl_context_wgl_class_init (GdkWin32GLContextWGLClass *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_wgl;
context_class->realize = gdk_win32_gl_context_realize_wgl;
gobject_class->dispose = gdk_win32_gl_context_dispose_wgl;
}
static void
gdk_win32_gl_context_wgl_init (GdkWin32GLContextWGL *wgl_context)
{
}
/* End section on WGL support */
/* Section on EGL/libANGLE support */
#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
struct _GdkWin32GLContextEGL
{
GdkWin32GLContext parent_instance;
EGLContext egl_context;
};
#define GDK_TYPE_WIN32_GL_CONTEXT_EGL (gdk_win32_gl_context_egl_get_type())
#define GDK_WIN32_GL_CONTEXT_EGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_WIN32_GL_CONTEXT_EGL, GdkWin32GLContextEGL))
#define GDK_IS_WIN32_GL_CONTEXT_EGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_WIN32_GL_CONTEXT_EGL))
typedef struct _GdkWin32GLContextClass GdkWin32GLContextEGLClass;
typedef struct _GdkWin32GLContextEGL GdkWin32GLContextEGL;
G_DEFINE_TYPE (GdkWin32GLContextEGL, gdk_win32_gl_context_egl, GDK_TYPE_WIN32_GL_CONTEXT)
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);
}
static void
gdk_win32_gl_context_dispose_egl (GObject *gobject)
{
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
GdkWin32GLContextEGL *context_egl = GDK_WIN32_GL_CONTEXT_EGL (context);
if (context_egl->egl_context != EGL_NO_CONTEXT)
{
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context));
if (eglGetCurrentContext () == context_egl->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_egl->egl_context);
context_egl->egl_context = EGL_NO_CONTEXT;
gdk_win32_gl_context_cleanup (context);
}
G_OBJECT_CLASS (gdk_win32_gl_context_parent_class)->dispose (gobject);
}
static gboolean
get_is_egl_force_redraw (GdkWindow *window)
{
/* We only need to call gdk_window_invalidate_rect () if necessary */
if (window->gl_paint_context != NULL && gdk_gl_context_get_use_es (window->gl_paint_context))
{
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
return impl->egl_force_redraw_all;
}
return FALSE;
}
static void
reset_egl_force_redraw (GdkWindow *window)
{
if (window->gl_paint_context != NULL && gdk_gl_context_get_use_es (window->gl_paint_context))
{
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
if (impl->egl_force_redraw_all)
impl->egl_force_redraw_all = FALSE;
}
}
static void
gdk_win32_gl_context_end_frame_egl (GdkGLContext *context,
cairo_region_t *painted,
cairo_region_t *damage)
{
GdkWindow *window = gdk_gl_context_get_window (context);
GdkWin32Display *display_win32 = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)));
GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
EGLSurface egl_surface = _gdk_win32_window_get_egl_surface (window, display_win32->egl_config, FALSE);
gboolean force_egl_redraw_all = get_is_egl_force_redraw (window);
gdk_gl_context_make_current (context);
if (context_win32->do_blit_swap && !force_egl_redraw_all)
gdk_gl_blit_region (window, painted, FALSE);
else if (force_egl_redraw_all)
{
GdkRectangle rect = {0, 0, gdk_window_get_width (window), gdk_window_get_height (window)};
/* We need to do gdk_window_invalidate_rect() so that we don't get glitches after maximizing or
* restoring or using aerosnap
*/
gdk_window_invalidate_rect (window, &rect, TRUE);
reset_egl_force_redraw (window);
}
eglSwapBuffers (display_win32->egl_disp, egl_surface);
}
static void
gdk_win32_display_init_egl (GdkWin32Display *display_win32)
{
EGLDisplay egl_disp;
if (display_win32->gl_type == GDK_WIN32_GL_NONE)
GDK_NOTE (OPENGL, g_message ("Falling back to GLES..."));
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;
}
display_win32->gl_type = GDK_WIN32_GL_NONE;
return;
}
display_win32->egl_disp = egl_disp;
display_win32->gl_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* EGL_KHR_surfaceless_context: %s\n",
display_win32->gl_version / 10,
display_win32->gl_version % 10,
eglQueryString (display_win32->egl_disp, EGL_VENDOR),
display_win32->hasEglSurfacelessContext ? "yes" : "no"));
display_win32->gl_type = GDK_WIN32_GL_EGL;
}
#define MAX_EGL_ATTRS 30
static gboolean
find_eglconfig_for_window (GdkWin32Display *display_win32,
gboolean need_alpha_bits,
GError **error)
{
EGLint attrs[MAX_EGL_ATTRS];
EGLint count;
EGLConfig *configs, chosen_config;
int i = 0;
EGLDisplay egl_disp;
if (display_win32->egl_min_swap_interval != 0 &&
display_win32->egl_config != NULL)
return TRUE;
egl_disp = display_win32->egl_disp;
attrs[i++] = EGL_CONFORMANT;
attrs[i++] = EGL_OPENGL_ES2_BIT;
attrs[i++] = EGL_SURFACE_TYPE;
attrs[i++] = EGL_WINDOW_BIT;
attrs[i++] = EGL_COLOR_BUFFER_TYPE;
attrs[i++] = EGL_RGB_BUFFER;
attrs[i++] = EGL_RED_SIZE;
attrs[i++] = 1;
attrs[i++] = EGL_GREEN_SIZE;
attrs[i++] = 1;
attrs[i++] = EGL_BLUE_SIZE;
attrs[i++] = 1;
if (need_alpha_bits)
{
attrs[i++] = EGL_ALPHA_SIZE;
attrs[i++] = 1;
}
else
{
attrs[i++] = EGL_ALPHA_SIZE;
attrs[i++] = EGL_DONT_CARE;
}
attrs[i++] = EGL_NONE;
g_assert (i < MAX_EGL_ATTRS);
if (!eglChooseConfig (display_win32->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_win32->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_win32->egl_disp, chosen_config,
EGL_MIN_SWAP_INTERVAL, &display_win32->egl_min_swap_interval))
{
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;
}
display_win32->egl_config = 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)
{
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
* if we do not request for ES3 or later
*/
if (major < 3)
{
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_EGL (share)->egl_context
: EGL_NO_CONTEXT,
context_attribs);
return ctx;
}
static gboolean
gdk_win32_gl_context_realize_egl (GdkGLContext *context,
GError **error)
{
GdkGLContext *share = gdk_gl_context_get_shared_context (context);
GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
GdkWindow *window = gdk_gl_context_get_window (context);
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_window_get_display (window));
/* These are the real EGL context items that we will want to use later */
EGLContext ctx;
gboolean debug_bit, compat_bit;
gboolean legacy_bit = FALSE;
/* request flags and specific versions for EGL context */
gint flags = 0;
gint major = 0;
gint minor = 0;
/* we are using GLES, so set early so that we get the correct GLES versions to request */
gdk_gl_context_set_use_es (context, TRUE);
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 (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"));
ctx = create_egl_context (display_win32->egl_disp,
display_win32->egl_config,
share,
flags,
major,
minor);
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));
GDK_WIN32_GL_CONTEXT_EGL (context)->egl_context = ctx;
/* OpenGL does not work with WS_EX_LAYERED enabled, so we need to
* disable WS_EX_LAYERED when we acquire a valid HGLRC
*/
impl->suppress_layered++;
/* if this is the first time a GL context is acquired for the window,
* disable layered windows by triggering update_style_bits()
*/
if (impl->suppress_layered == 1)
_gdk_win32_window_update_style_bits (window);
/* Ensure that any other context is created with a legacy bit set */
gdk_gl_context_set_is_legacy (context, legacy_bit);
return TRUE;
}
void
gdk_win32_window_invalidate_egl_framebuffer (GdkWindow *window)
{
/* 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
*/
if (window->gl_paint_context != NULL && gdk_gl_context_get_use_es (window->gl_paint_context))
{
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
impl->egl_force_redraw_all = TRUE;
}
}
static gboolean
gdk_win32_display_make_egl_context_current (GdkDisplay *display,
GdkGLContext *context)
{
GdkWin32GLContext *context_win32;
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
GdkWindow *window;
EGLSurface egl_surface;
if (context == NULL)
{
eglMakeCurrent (display_win32->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
return TRUE;
}
context_win32 = GDK_WIN32_GL_CONTEXT (context);
window = gdk_gl_context_get_window (context);
if (context_win32->is_attached || !display_win32->hasEglSurfacelessContext)
egl_surface = _gdk_win32_window_get_egl_surface (window,
display_win32->egl_config,
!context_win32->is_attached);
else
egl_surface = EGL_NO_SURFACE;
if (!eglMakeCurrent (display_win32->egl_disp,
egl_surface,
egl_surface,
GDK_WIN32_GL_CONTEXT_EGL (context)->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");
return TRUE;
}
static void
gdk_win32_gl_context_egl_class_init (GdkWin32GLContextEGLClass *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_egl;
context_class->realize = gdk_win32_gl_context_realize_egl;
gobject_class->dispose = gdk_win32_gl_context_dispose_egl;
}
static void
gdk_win32_gl_context_egl_init (GdkWin32GLContextEGL *egl_context)
{
}
#else /* GDK_WIN32_ENABLE_EGL */
/* define EGL stuff as no-op macros or functions if it is not enabled */
static void
gdk_win32_display_init_egl (GdkWin32Display *display_win32)
{
GDK_NOTE (OPENGL, g_message ("Cannot %s GLES contexts: no GLES support",
display_win32->gl_type == GDK_WIN32_GL_PENDING ?
"create" : "fallback to"));
display_win32->gl_type = GDK_WIN32_GL_NONE;
}
#define gdk_win32_display_make_egl_context_current(disp,ctx) FALSE
void
gdk_win32_window_invalidate_egl_framebuffer (GdkWindow *window)
{
}
static gboolean
find_eglconfig_for_window (GdkWin32Display *display_win32,
gboolean need_alpha_bits,
GError **error)
{
return FALSE;
}
#endif /* !GDK_WIN32_ENABLE_EGL */
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);
}
static void
gdk_win32_gl_context_init (GdkWin32GLContext *self)
{
}
void
gdk_win32_window_invalidate_for_new_frame (GdkWindow *window,
cairo_region_t *update_area)
{
cairo_rectangle_int_t window_rect;
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);
}
}
static void
gdk_win32_display_init_gl (GdkDisplay *display,
GdkGLContext *share,
const gboolean need_alpha_bits)
{
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
gint best_idx = 0;
gboolean disable_wgl = FALSE;
if (display_win32->gl_type == GDK_WIN32_GL_WGL ||
display_win32->gl_type == GDK_WIN32_GL_EGL)
return;
/*
* We must disable WGL if we are using GDK_GL=gles or if the
* existing shared GLContext is a GLES context
*/
disable_wgl = ((_gdk_gl_flags & GDK_GL_GLES) != 0) ||
(share != NULL && gdk_gl_context_get_use_es (share));
if (!disable_wgl)
gdk_win32_display_init_wgl (display_win32, need_alpha_bits);
if (display_win32->gl_type == GDK_WIN32_GL_PENDING ||
display_win32->gl_type == GDK_WIN32_GL_NONE)
gdk_win32_display_init_egl (display_win32);
}
GdkGLContext *
gdk_win32_window_create_gl_context (GdkWindow *window,
gboolean attached,
GdkGLContext *share,
GError **error)
{
GdkDisplay *display = gdk_window_get_display (window);
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_window_get_display (window));
GdkWin32GLContext *context_win32 = NULL;
GdkVisual *visual = gdk_window_get_visual (window);
gboolean need_alpha_bits = (visual == gdk_screen_get_rgba_visual (gdk_display_get_default_screen (display)));
/* Acquire and store up the Windows-specific HWND and HDC */
HDC hdc = GetDC (GDK_WINDOW_HWND (window));
/* display_win32->hdc_egl_temp should *not* be destroyed here! It is destroyed at dispose()! */
display_win32->hdc_egl_temp = hdc;
gdk_win32_display_init_gl (display,
share,
need_alpha_bits);
if (display_win32->gl_type == GDK_WIN32_GL_NONE)
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("No GL implementation is available"));
return NULL;
}
if (display_win32->gl_type == GDK_WIN32_GL_EGL &&
!find_eglconfig_for_window (display_win32, need_alpha_bits, error))
{
display_win32->gl_type = GDK_WIN32_GL_NONE;
return NULL;
}
if (display_win32->gl_type == GDK_WIN32_GL_WGL)
context_win32 = GDK_WIN32_GL_CONTEXT (g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_WGL,
"display", display,
"window", window,
"shared-context", share,
NULL));
#ifdef GDK_WIN32_ENABLE_EGL
else if (display_win32->gl_type == GDK_WIN32_GL_EGL)
context_win32 = GDK_WIN32_GL_CONTEXT (g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_EGL,
"display", display,
"window", window,
"shared-context", share,
NULL));
#endif
context_win32->need_alpha_bits = need_alpha_bits;
context_win32->gl_hdc = hdc;
context_win32->is_attached = attached;
return GDK_GL_CONTEXT (context_win32);
}
gboolean
gdk_win32_display_make_gl_context_current (GdkDisplay *display,
GdkGLContext *context)
{
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
if (display_win32->gl_type == GDK_WIN32_GL_WGL)
return gdk_win32_display_make_wgl_context_current (display, context);
if (display_win32->gl_type == GDK_WIN32_GL_EGL)
return gdk_win32_display_make_egl_context_current (display, context);
g_assert_not_reached ();
return FALSE;
}
/**
* 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)
{
GdkWin32Display *display_win32 = NULL;
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
if (!GDK_IS_WIN32_DISPLAY (display))
return FALSE;
display_win32 = GDK_WIN32_DISPLAY (display);
if (display_win32->gl_type == GDK_WIN32_GL_PENDING)
gdk_win32_display_init_gl (display, NULL, FALSE);
if (display_win32->gl_type == GDK_WIN32_GL_NONE)
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;
}