mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 13:41:07 +00:00
gdkglcontext-win32-wgl.c: Fix using wglChoosePixelFormatARB()
If we are querying the best supported pixel format for our HDC via wglChoosePixelFormatARB() (i.e. we have the WGL_ARB_pixel_format extension), it may return a pixel format that is different from the pixel format that we used for the dummy context that we have setup, in order to, well, run wglChoosePixelFormatARB(), which sadly requires a WGL context (HGLRC) to be current in order to use it, which means the dummy HDC already has a pixel format that has been set (notice that each HDC is only allowed to have its pixel format to be set *once*). This is notably the case on Intel display drivers. Since we are emulating surfaceless GL contexts, we are using the dummy GL context (and thus dummy HDC that is derived from the notification HWND used in GdkWin32Display) for doing that, we would get into trouble if th actual HDC from the GdkWin32Surface has a different pixel format set. So, as a result, in order to fix this situation, we do the following: * Create yet another dummy HWND in order to grab the HDC to query for the capabilities the GL drivers support, and to call wglChoosePixelFormatARB() as appropriate (or ChoosePixelFormat()) for the final pixel format that we use. * Ditch the dummy GL context, HDC and HWND after obtaining the pixel format. * Then set the final pixel format that we obtained onto the HDC that is derived from the HWND used in GdkWin32Display for notifications, which will become our new dummy HDC. * Create a new dummy HGLRC for use with the new dummy HDC to emulate surfaceless GL support.
This commit is contained in:
parent
347561fa68
commit
50ef36d387
@ -646,15 +646,15 @@ gdk_win32_display_dispose (GObject *object)
|
||||
{
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (object);
|
||||
|
||||
if (display_win32->dummy_context_wgl.hglrc != NULL)
|
||||
{
|
||||
wglMakeCurrent (NULL, NULL);
|
||||
wglDeleteContext (display_win32->dummy_context_wgl.hglrc);
|
||||
display_win32->dummy_context_wgl.hglrc = NULL;
|
||||
}
|
||||
|
||||
if (display_win32->hwnd != NULL)
|
||||
{
|
||||
if (display_win32->dummy_context_wgl.hglrc != NULL)
|
||||
{
|
||||
wglMakeCurrent (NULL, NULL);
|
||||
wglDeleteContext (display_win32->dummy_context_wgl.hglrc);
|
||||
display_win32->dummy_context_wgl.hglrc = NULL;
|
||||
}
|
||||
|
||||
DestroyWindow (display_win32->hwnd);
|
||||
display_win32->hwnd = NULL;
|
||||
}
|
||||
@ -1129,7 +1129,6 @@ gdk_win32_display_get_monitor_scale_factor (GdkWin32Display *display_win32,
|
||||
{
|
||||
if (GDK_WIN32_SURFACE (surface)->hdc == NULL)
|
||||
GDK_WIN32_SURFACE (surface)->hdc = GetDC (GDK_SURFACE_HWND (surface));
|
||||
|
||||
hdc = GDK_WIN32_SURFACE (surface)->hdc;
|
||||
}
|
||||
else
|
||||
@ -1184,11 +1183,6 @@ gdk_win32_display_init_gl (GdkDisplay *display,
|
||||
HDC init_gl_hdc = NULL;
|
||||
GdkGLContext *context;
|
||||
|
||||
if (display_win32->dummy_context_wgl.hdc == NULL)
|
||||
display_win32->dummy_context_wgl.hdc = GetDC (display_win32->hwnd);
|
||||
|
||||
init_gl_hdc = display_win32->dummy_context_wgl.hdc;
|
||||
|
||||
/*
|
||||
* No env vars set, do the regular GL initialization, first WGL and then EGL,
|
||||
* as WGL is the more tried-and-tested configuration.
|
||||
@ -1201,6 +1195,8 @@ gdk_win32_display_init_gl (GdkDisplay *display,
|
||||
*/
|
||||
if (gdk_display_get_debug_flags (display) & (GDK_DEBUG_GL_EGL|GDK_DEBUG_GL_GLES))
|
||||
{
|
||||
init_gl_hdc = GetDC (display_win32->hwnd);
|
||||
|
||||
if (gdk_display_init_egl (display,
|
||||
EGL_PLATFORM_ANGLE_ANGLE,
|
||||
init_gl_hdc,
|
||||
@ -1218,12 +1214,14 @@ gdk_win32_display_init_gl (GdkDisplay *display,
|
||||
#endif
|
||||
|
||||
context = gdk_win32_display_init_wgl (display, error);
|
||||
|
||||
if (context)
|
||||
return context;
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
g_clear_error (error);
|
||||
|
||||
init_gl_hdc = GetDC (display_win32->hwnd);
|
||||
if (gdk_display_init_egl (display,
|
||||
EGL_PLATFORM_ANGLE_ANGLE,
|
||||
init_gl_hdc,
|
||||
|
@ -108,6 +108,7 @@ typedef enum {
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HWND hwnd;
|
||||
HDC hdc;
|
||||
HGLRC hglrc;
|
||||
} GdkWin32GLDummyContextWGL;
|
||||
|
@ -140,7 +140,8 @@ get_wgl_pfd (HDC hdc,
|
||||
|
||||
pfd->nSize = sizeof (PIXELFORMATDESCRIPTOR);
|
||||
|
||||
if (display_win32 != NULL && display_win32->hasWglARBPixelFormat)
|
||||
if (display_win32 != NULL &&
|
||||
display_win32->hasWglARBPixelFormat)
|
||||
{
|
||||
UINT num_formats;
|
||||
int colorbits = GetDeviceCaps (hdc, BITSPIXEL);
|
||||
@ -247,6 +248,43 @@ gdk_init_dummy_wgl_context (GdkWin32Display *display_win32)
|
||||
return best_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a dummy HWND to init GL, sadly we can't just use the
|
||||
* HWND that we use for notifications as we may only call
|
||||
* SetPixelFormat() on an HDC once, and that notification HWND
|
||||
* uses the CS_OWNDC style meaning that even if we were to call
|
||||
* DeleteDC() on it, we would get the exact same HDC when we call
|
||||
* GetDC() on it later, meaning SetPixelFormat() cannot be used
|
||||
* again on the HDC that we acquire from the notification HWND.
|
||||
*/
|
||||
static HWND
|
||||
create_dummy_gl_window (void)
|
||||
{
|
||||
WNDCLASS wclass = { 0, };
|
||||
ATOM klass;
|
||||
HWND hwnd;
|
||||
|
||||
wclass.lpszClassName = "GdkGLDummyWindow";
|
||||
wclass.lpfnWndProc = DefWindowProc;
|
||||
wclass.hInstance = _gdk_app_hmodule;
|
||||
wclass.style = CS_OWNDC;
|
||||
|
||||
klass = RegisterClass (&wclass);
|
||||
if (klass)
|
||||
{
|
||||
hwnd = CreateWindow (MAKEINTRESOURCE (klass),
|
||||
NULL, WS_POPUP,
|
||||
0, 0, 0, 0, NULL, NULL,
|
||||
_gdk_app_hmodule, NULL);
|
||||
if (!hwnd)
|
||||
{
|
||||
UnregisterClass (MAKEINTRESOURCE (klass), _gdk_app_hmodule);
|
||||
}
|
||||
}
|
||||
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
GdkGLContext *
|
||||
gdk_win32_display_init_wgl (GdkDisplay *display,
|
||||
GError **error)
|
||||
@ -263,6 +301,15 @@ gdk_win32_display_init_wgl (GdkDisplay *display,
|
||||
* dummy GL Context, it is used to query functions
|
||||
* and used for other stuff as well
|
||||
*/
|
||||
|
||||
if (display_win32->dummy_context_wgl.hdc == NULL)
|
||||
{
|
||||
display_win32->dummy_context_wgl.hwnd = create_dummy_gl_window ();
|
||||
|
||||
if (display_win32->dummy_context_wgl.hwnd != NULL)
|
||||
display_win32->dummy_context_wgl.hdc = GetDC (display_win32->dummy_context_wgl.hwnd);
|
||||
}
|
||||
|
||||
best_idx = gdk_init_dummy_wgl_context (display_win32);
|
||||
hdc = display_win32->dummy_context_wgl.hdc;
|
||||
|
||||
@ -521,34 +568,50 @@ create_wgl_context (GdkGLContext *context,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_wgl_pixformat_for_hdc (HDC hdc,
|
||||
set_wgl_pixformat_for_hdc (GdkWin32Display *display_win32,
|
||||
HDC *hdc,
|
||||
int *best_idx,
|
||||
GdkWin32Display *display_win32)
|
||||
gboolean *recreate_dummy_context)
|
||||
{
|
||||
gboolean already_checked = TRUE;
|
||||
*best_idx = GetPixelFormat (hdc);
|
||||
gboolean skip_acquire = FALSE;
|
||||
gboolean set_pixel_format_result = FALSE;
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
|
||||
/* one is only allowed to call SetPixelFormat(), and so ChoosePixelFormat()
|
||||
* one single time per window HDC
|
||||
*/
|
||||
if (*best_idx == 0)
|
||||
GDK_NOTE (OPENGL, g_print ("requesting pixel format...\n"));
|
||||
*best_idx = get_wgl_pfd (*hdc, &pfd, display_win32);
|
||||
|
||||
if (display_win32->dummy_context_wgl.hwnd != NULL)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
gboolean set_pixel_format_result = FALSE;
|
||||
/*
|
||||
* Ditch the initial dummy HDC, HGLRC and HWND used to initialize WGL,
|
||||
* we want to ensure that the HDC of the notification HWND that we will
|
||||
* also use for our new dummy HDC will have the correct pixel format set
|
||||
*/
|
||||
wglDeleteContext (display_win32->dummy_context_wgl.hglrc);
|
||||
display_win32->dummy_context_wgl.hdc = GetDC (display_win32->hwnd);
|
||||
*hdc = display_win32->dummy_context_wgl.hdc;
|
||||
*recreate_dummy_context = TRUE;
|
||||
|
||||
GDK_NOTE (OPENGL, g_print ("requesting pixel format...\n"));
|
||||
already_checked = FALSE;
|
||||
*best_idx = get_wgl_pfd (hdc, &pfd, display_win32);
|
||||
|
||||
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;
|
||||
DestroyWindow (display_win32->dummy_context_wgl.hwnd);
|
||||
display_win32->dummy_context_wgl.hwnd = NULL;
|
||||
}
|
||||
|
||||
GDK_NOTE (OPENGL, g_print ("%s""requested and set pixel format: %d\n", already_checked ? "already " : "", *best_idx));
|
||||
if (GetPixelFormat (*hdc) != 0)
|
||||
{
|
||||
skip_acquire = TRUE;
|
||||
set_pixel_format_result = TRUE;
|
||||
}
|
||||
else 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", skip_acquire ? "already " : "", *best_idx));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -564,8 +627,9 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
|
||||
/* request flags and specific versions for core (3.2+) WGL context */
|
||||
int flags = 0;
|
||||
HGLRC hglrc;
|
||||
int pixel_format;
|
||||
int pixel_format = 0;
|
||||
HDC hdc;
|
||||
gboolean recreate_dummy_context = FALSE;
|
||||
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
@ -591,9 +655,10 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
|
||||
else
|
||||
hdc = display_win32->dummy_context_wgl.hdc;
|
||||
|
||||
if (!set_wgl_pixformat_for_hdc (hdc,
|
||||
if (!set_wgl_pixformat_for_hdc (display_win32,
|
||||
&hdc,
|
||||
&pixel_format,
|
||||
display_win32))
|
||||
&recreate_dummy_context))
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
|
||||
@ -617,6 +682,28 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
|
||||
flags,
|
||||
legacy_bit,
|
||||
error);
|
||||
|
||||
if (recreate_dummy_context)
|
||||
{
|
||||
display_win32->dummy_context_wgl.hglrc =
|
||||
create_wgl_context (context,
|
||||
display_win32->dummy_context_wgl.hdc,
|
||||
display_win32->hasWglARBCreateContext,
|
||||
NULL,
|
||||
flags,
|
||||
legacy_bit,
|
||||
error);
|
||||
|
||||
if (display_win32->dummy_context_wgl.hglrc == NULL)
|
||||
{
|
||||
if (hglrc != NULL)
|
||||
{
|
||||
wglDeleteContext (hglrc);
|
||||
hglrc = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hglrc == NULL)
|
||||
return 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user