summaryrefslogtreecommitdiff
path: root/gdk
diff options
context:
space:
mode:
authorChun-wei Fan <fanchunwei@src.gnome.org>2023-05-03 17:58:54 +0800
committerChun-wei Fan <fanchunwei@src.gnome.org>2023-05-09 18:15:23 +0800
commit50ef36d38794aab6361c94cdb3fa780e7fc4d1bc (patch)
tree8554e1e1b4b5dd4533564b7cc9cc8e0125b8c9d8 /gdk
parent347561fa68457796454d2e195f83c5ae42e87235 (diff)
downloadgtk+-50ef36d38794aab6361c94cdb3fa780e7fc4d1bc.tar.gz
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.
Diffstat (limited to 'gdk')
-rw-r--r--gdk/win32/gdkdisplay-win32.c24
-rw-r--r--gdk/win32/gdkdisplay-win32.h1
-rw-r--r--gdk/win32/gdkglcontext-win32-wgl.c131
3 files changed, 121 insertions, 35 deletions
diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c
index 7952089f52..fb7ddd858b 100644
--- a/gdk/win32/gdkdisplay-win32.c
+++ b/gdk/win32/gdkdisplay-win32.c
@@ -646,15 +646,15 @@ gdk_win32_display_dispose (GObject *object)
{
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (object);
- if (display_win32->hwnd != NULL)
+ if (display_win32->dummy_context_wgl.hglrc != 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;
- }
+ wglMakeCurrent (NULL, NULL);
+ wglDeleteContext (display_win32->dummy_context_wgl.hglrc);
+ display_win32->dummy_context_wgl.hglrc = NULL;
+ }
+ if (display_win32->hwnd != 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,
diff --git a/gdk/win32/gdkdisplay-win32.h b/gdk/win32/gdkdisplay-win32.h
index fd2ab0466b..acf429c83f 100644
--- a/gdk/win32/gdkdisplay-win32.h
+++ b/gdk/win32/gdkdisplay-win32.h
@@ -108,6 +108,7 @@ typedef enum {
typedef struct
{
+ HWND hwnd;
HDC hdc;
HGLRC hglrc;
} GdkWin32GLDummyContextWGL;
diff --git a/gdk/win32/gdkglcontext-win32-wgl.c b/gdk/win32/gdkglcontext-win32-wgl.c
index 9a7e5f3b52..02a4b1f47f 100644
--- a/gdk/win32/gdkglcontext-win32-wgl.c
+++ b/gdk/win32/gdkglcontext-win32-wgl.c
@@ -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)
- {
- 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, &pfd, display_win32);
+ GDK_NOTE (OPENGL, g_print ("requesting pixel format...\n"));
+ *best_idx = get_wgl_pfd (*hdc, &pfd, display_win32);
- if (*best_idx != 0)
- set_pixel_format_result = SetPixelFormat (hdc, *best_idx, &pfd);
+ if (display_win32->dummy_context_wgl.hwnd != NULL)
+ {
+ /*
+ * 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;
+
+ DestroyWindow (display_win32->dummy_context_wgl.hwnd);
+ display_win32->dummy_context_wgl.hwnd = NULL;
+ }
- /* ChoosePixelFormat() or SetPixelFormat() failed, bail out */
- if (*best_idx == 0 || !set_pixel_format_result)
- return FALSE;
+ 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);
- GDK_NOTE (OPENGL, g_print ("%s""requested and set pixel format: %d\n", already_checked ? "already " : "", *best_idx));
+ /* 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;