Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58846
Wine D3D resets the window pixel format to its original value when an internal pixel format was requested and the context done being used, and requests the internal pixel format again before it is used again. When internal pixel format and window pixel format don't match this causes any previously created OpenGL surface with a different format to be released (and destroyed as no context is current with it), creating a new one with the new format, back and forth.
What we actually need here, is to keep the wined3d OpenGL client surface, with the internal pixel format, alive as long as it is being referenced by wined3d, as well as any OpenGL client surface that may have been created, with the window pixel format, by the application itself.
It's not possible to rely on DCs for application-created OpenGL surfaces, as the application is free to release its DC and retrieve another one later on for the same window while still expecting it to use the same OpenGL surface. However with wined3d, we know that the DCs are being kept referenced until the context is being destroyed so we can safely use them to store the wined3d OpenGL surface.
-- v3: wined3d: Remove now unnecessary pixel format restoration. win32u: Get rid of window internal pixel format. win32u: Keep internal pixel format and surfaces on the DCs. wined3d: Call wglSetPixelFormatWINE before releasing context DC.
From: Rémi Bernon rbernon@codeweavers.com
With format == 0 if internal pixel format was previously requested.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58846 --- dlls/wined3d/context_gl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c index ac1b9370fc1..ad2a50a66f1 100644 --- a/dlls/wined3d/context_gl.c +++ b/dlls/wined3d/context_gl.c @@ -1260,6 +1260,7 @@ success:
static BOOL wined3d_context_gl_set_gl_context(struct wined3d_context_gl *context_gl) { + const struct wined3d_gl_info *gl_info = context_gl->gl_info; struct wined3d_device_gl *device_gl = wined3d_device_gl(context_gl->c.device); BOOL backup = FALSE;
@@ -1286,7 +1287,10 @@ static BOOL wined3d_context_gl_set_gl_context(struct wined3d_context_gl *context return FALSE; }
+ if (context_gl->internal_format_set) + GL_EXTCALL(wglSetPixelFormatWINE(context_gl->dc, 0)); wined3d_release_dc(context_gl->window, context_gl->dc); + if (!(context_gl->dc = wined3d_device_gl_get_backup_dc(device_gl))) { wined3d_context_gl_set_current(NULL); @@ -1332,6 +1336,8 @@ static void context_restore_gl_context(const struct wined3d_gl_info *gl_info, HD
static void wined3d_context_gl_update_window(struct wined3d_context_gl *context_gl) { + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + if (!context_gl->c.swapchain) return;
@@ -1342,7 +1348,11 @@ static void wined3d_context_gl_update_window(struct wined3d_context_gl *context_ context_gl, context_gl->window, context_gl->c.swapchain->win_handle);
if (context_gl->dc) + { + if (context_gl->internal_format_set) + GL_EXTCALL(wglSetPixelFormatWINE(context_gl->dc, 0)); wined3d_release_dc(context_gl->window, context_gl->dc); + }
context_gl->window = context_gl->c.swapchain->win_handle; context_gl->dc_is_private = FALSE; @@ -1542,6 +1552,8 @@ static void wined3d_context_gl_cleanup(struct wined3d_context_gl *context_gl) else if (wglGetCurrentContext() && !wglMakeCurrent(NULL, NULL)) ERR("Failed to disable GL context.\n");
+ if (context_gl->internal_format_set) + GL_EXTCALL(wglSetPixelFormatWINE(context_gl->dc, 0)); wined3d_release_dc(context_gl->window, context_gl->dc);
if (!wglDeleteContext(context_gl->gl_ctx))
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58846 --- dlls/win32u/opengl.c | 103 ++++++++++++++++++++++++++++++------------- dlls/win32u/window.c | 2 +- 2 files changed, 73 insertions(+), 32 deletions(-)
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index fc0be5795d4..714318d26fb 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1269,24 +1269,32 @@ static const char *win32u_wglGetExtensionsStringEXT(void) return wgl_extensions; }
-static int get_dc_pixel_format( HDC hdc, BOOL internal ) +static int get_dc_pixel_format( HDC hdc, BOOL *is_display ) { - int ret = 0; - HWND hwnd; + int ret; DC *dc;
- if ((hwnd = NtUserWindowFromDC( hdc ))) - ret = get_window_pixel_format( hwnd, internal ); - else if ((dc = get_dc_ptr( hdc ))) - { - BOOL is_display = dc->is_display; - ret = dc->pixel_format; - release_dc_ptr( dc ); + if (!(dc = get_dc_ptr( hdc ))) return -1; + if (is_display) *is_display = dc->is_display; + ret = dc->pixel_format; + release_dc_ptr( dc ); + + return ret; +}
+static int win32u_wglGetPixelFormat( HDC hdc ) +{ + BOOL is_display = FALSE; + int format; + HWND hwnd; + + if ((hwnd = NtUserWindowFromDC( hdc ))) format = get_window_pixel_format( hwnd, FALSE ); + else if ((format = get_dc_pixel_format( hdc, &is_display )) >= 0) + { /* Offscreen formats can't be used with traditional WGL calls. As has been * verified on Windows GetPixelFormat doesn't fail but returns 1. */ - if (is_display && ret >= 0 && ret > onscreen_count) ret = 1; + if (is_display && format > onscreen_count) format = 1; } else { @@ -1295,13 +1303,7 @@ static int get_dc_pixel_format( HDC hdc, BOOL internal ) return -1; }
- TRACE( "%p/%p -> %d\n", hdc, hwnd, ret ); - return ret; -} - -static int win32u_wglGetPixelFormat( HDC hdc ) -{ - int format = get_dc_pixel_format( hdc, FALSE ); + TRACE( "%p/%p -> %d\n", hdc, hwnd, format ); return format > 0 ? format : 0; }
@@ -1466,7 +1468,7 @@ static BOOL flush_memory_dc( struct wgl_context *context, HDC hdc, BOOL write, v return ret; }
-static BOOL set_dc_pixel_format( HDC hdc, int new_format, BOOL internal ) +static BOOL win32u_wglSetPixelFormat( HDC hdc, int new_format, const PIXELFORMATDESCRIPTOR *pfd ) { const struct opengl_funcs *funcs = &display_funcs; UINT total, onscreen; @@ -1486,9 +1488,9 @@ static BOOL set_dc_pixel_format( HDC hdc, int new_format, BOOL internal ) return FALSE; }
- TRACE( "%p/%p format %d, internal %u\n", hdc, hwnd, new_format, internal ); + TRACE( "%p/%p format %d\n", hdc, hwnd, new_format );
- if ((old_format = get_window_pixel_format( hwnd, FALSE )) && !internal) return old_format == new_format; + if ((old_format = get_window_pixel_format( hwnd, FALSE ))) return old_format == new_format;
if ((drawable = get_window_unused_drawable( hwnd, new_format ))) { @@ -1497,21 +1499,52 @@ static BOOL set_dc_pixel_format( HDC hdc, int new_format, BOOL internal ) opengl_drawable_release( drawable ); }
- return set_window_pixel_format( hwnd, new_format, internal ); + return set_window_pixel_format( hwnd, new_format, FALSE ); }
- TRACE( "%p/%p format %d, internal %u\n", hdc, hwnd, new_format, internal ); + TRACE( "%p/%p format %d\n", hdc, hwnd, new_format ); return NtGdiSetPixelFormat( hdc, new_format ); }
-static BOOL win32u_wglSetPixelFormat( HDC hdc, int format, const PIXELFORMATDESCRIPTOR *pfd ) +static BOOL win32u_wglSetPixelFormatWINE( HDC hdc, int new_format ) { - return set_dc_pixel_format( hdc, format, FALSE ); -} + const struct opengl_funcs *funcs = &display_funcs; + struct opengl_drawable *drawable; + UINT total, onscreen; + HWND hwnd; + DC *dc;
-static BOOL win32u_wglSetPixelFormatWINE( HDC hdc, int format ) -{ - return set_dc_pixel_format( hdc, format, TRUE ); + if (!(hwnd = NtUserWindowFromDC( hdc ))) return FALSE; + + TRACE( "%p/%p format %d\n", hdc, hwnd, new_format ); + + funcs->p_get_pixel_formats( NULL, 0, &total, &onscreen ); + if (new_format < 0 || new_format > total) return FALSE; + if (new_format > onscreen) + { + WARN( "Invalid format %d for %p/%p\n", new_format, hdc, hwnd ); + return FALSE; + } + + if (!(dc = get_dc_ptr( hdc ))) return FALSE; + dc->pixel_format = new_format; + drawable = dc->opengl_drawable; + dc->opengl_drawable = NULL; + release_dc_ptr( dc ); + + if (drawable && drawable->format != new_format) + { + opengl_drawable_release( drawable ); + drawable = NULL; + } + if (new_format && (drawable || (drawable = get_window_unused_drawable( hwnd, new_format )))) + { + set_window_opengl_drawable( hwnd, drawable, TRUE ); + set_dc_opengl_drawable( hdc, drawable ); + opengl_drawable_release( drawable ); + } + + return TRUE; }
static PROC win32u_wglGetProcAddress( const char *name ) @@ -1581,6 +1614,10 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H struct wgl_context *previous = NtCurrentTeb()->glContext; BOOL ret = FALSE;
+ /* retrieve the D3D internal drawables from the DCs if they have any */ + if (draw_hdc && !context->draw) context->draw = get_dc_opengl_drawable( draw_hdc ); + if (read_hdc && !context->read) context->read = get_dc_opengl_drawable( read_hdc ); + new_draw = get_updated_drawable( draw_hdc, context->format, context->draw ); if (!draw_hdc && context->draw == context->read) opengl_drawable_add_ref( (new_read = new_draw) ); else if (draw_hdc && draw_hdc == read_hdc) opengl_drawable_add_ref( (new_read = new_draw) ); @@ -1684,10 +1721,12 @@ static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct return TRUE; }
- if ((format = get_dc_pixel_format( draw_hdc, TRUE )) <= 0) + if ((format = get_dc_pixel_format( draw_hdc, NULL )) <= 0 && + (format = get_window_pixel_format( NtUserWindowFromDC( draw_hdc ), FALSE )) <= 0) { WARN( "Invalid draw_hdc %p format %u\n", draw_hdc, format ); if (!format) RtlSetLastWin32Error( ERROR_INVALID_PIXEL_FORMAT ); + else RtlSetLastWin32Error( ERROR_INVALID_HANDLE ); return FALSE; } if (context->format != format) @@ -2144,9 +2183,11 @@ static BOOL win32u_wgl_context_reset( struct wgl_context *context, HDC hdc, stru context->driver_private = NULL; if (!hdc) return TRUE;
- if ((format = get_dc_pixel_format( hdc, TRUE )) <= 0) + if ((format = get_dc_pixel_format( hdc, NULL )) <= 0 && + (format = get_window_pixel_format( NtUserWindowFromDC( hdc ), FALSE )) <= 0) { if (!format) RtlSetLastWin32Error( ERROR_INVALID_PIXEL_FORMAT ); + else RtlSetLastWin32Error( ERROR_INVALID_HANDLE ); return FALSE; } if (!driver_funcs->p_context_create( format, share_private, attribs, &context->driver_private )) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index c5c5d0522c8..8a026a3c189 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1568,7 +1568,7 @@ int get_window_pixel_format( HWND hwnd, BOOL internal ) if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS) { WARN( "getting format on win %p not supported\n", hwnd ); - return 0; + return -1; }
ret = internal && win->internal_pixel_format ? win->internal_pixel_format : win->pixel_format;
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58846 --- dlls/win32u/ntuser_private.h | 1 - dlls/win32u/opengl.c | 10 +++++----- dlls/win32u/win32u_private.h | 4 ++-- dlls/win32u/window.c | 18 ++++++------------ 4 files changed, 13 insertions(+), 20 deletions(-)
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 1d0131e5886..a9540abb576 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -72,7 +72,6 @@ typedef struct tagWND struct tagDIALOGINFO *dlgInfo; /* Dialog additional info (dialogs only) */ int swap_interval; /* OpenGL surface swap interval */ int pixel_format; /* Pixel format set by the graphics driver */ - int internal_pixel_format; /* Internal pixel format set via WGL_WINE_pixel_format_passthrough */ int cbWndExtra; /* class cbWndExtra at window creation */ DWORD_PTR userdata; /* User private data */ DWORD wExtra[1]; /* Window extra bytes */ diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 714318d26fb..7c733a4ced0 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1288,7 +1288,7 @@ static int win32u_wglGetPixelFormat( HDC hdc ) int format; HWND hwnd;
- if ((hwnd = NtUserWindowFromDC( hdc ))) format = get_window_pixel_format( hwnd, FALSE ); + if ((hwnd = NtUserWindowFromDC( hdc ))) format = get_window_pixel_format( hwnd ); else if ((format = get_dc_pixel_format( hdc, &is_display )) >= 0) { /* Offscreen formats can't be used with traditional WGL calls. As has been @@ -1490,7 +1490,7 @@ static BOOL win32u_wglSetPixelFormat( HDC hdc, int new_format, const PIXELFORMAT
TRACE( "%p/%p format %d\n", hdc, hwnd, new_format );
- if ((old_format = get_window_pixel_format( hwnd, FALSE ))) return old_format == new_format; + if ((old_format = get_window_pixel_format( hwnd ))) return old_format == new_format;
if ((drawable = get_window_unused_drawable( hwnd, new_format ))) { @@ -1499,7 +1499,7 @@ static BOOL win32u_wglSetPixelFormat( HDC hdc, int new_format, const PIXELFORMAT opengl_drawable_release( drawable ); }
- return set_window_pixel_format( hwnd, new_format, FALSE ); + return set_window_pixel_format( hwnd, new_format ); }
TRACE( "%p/%p format %d\n", hdc, hwnd, new_format ); @@ -1722,7 +1722,7 @@ static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct }
if ((format = get_dc_pixel_format( draw_hdc, NULL )) <= 0 && - (format = get_window_pixel_format( NtUserWindowFromDC( draw_hdc ), FALSE )) <= 0) + (format = get_window_pixel_format( NtUserWindowFromDC( draw_hdc ) )) <= 0) { WARN( "Invalid draw_hdc %p format %u\n", draw_hdc, format ); if (!format) RtlSetLastWin32Error( ERROR_INVALID_PIXEL_FORMAT ); @@ -2184,7 +2184,7 @@ static BOOL win32u_wgl_context_reset( struct wgl_context *context, HDC hdc, stru if (!hdc) return TRUE;
if ((format = get_dc_pixel_format( hdc, NULL )) <= 0 && - (format = get_window_pixel_format( NtUserWindowFromDC( hdc ), FALSE )) <= 0) + (format = get_window_pixel_format( NtUserWindowFromDC( hdc ) )) <= 0) { if (!format) RtlSetLastWin32Error( ERROR_INVALID_PIXEL_FORMAT ); else RtlSetLastWin32Error( ERROR_INVALID_HANDLE ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index ba0a9834d9f..3cc25d90d5b 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -275,8 +275,8 @@ extern BOOL is_window_enabled( HWND hwnd ); extern BOOL is_window_unicode( HWND hwnd ); extern BOOL is_window_visible( HWND hwnd ); extern BOOL is_zoomed( HWND hwnd ); -extern BOOL set_window_pixel_format( HWND hwnd, int format, BOOL internal ); -extern int get_window_pixel_format( HWND hwnd, BOOL internal ); +extern BOOL set_window_pixel_format( HWND hwnd, int format ); +extern int get_window_pixel_format( HWND hwnd ); extern DWORD get_window_long( HWND hwnd, INT offset ); extern ULONG_PTR get_window_long_ptr( HWND hwnd, INT offset, BOOL ansi ); extern BOOL get_window_rect( HWND hwnd, RECT *rect, UINT dpi ); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 8a026a3c189..c4ca7e8169f 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1538,7 +1538,7 @@ LONG_PTR WINAPI NtUserSetWindowLongPtr( HWND hwnd, INT offset, LONG_PTR newval, return set_window_long( hwnd, offset, sizeof(LONG_PTR), newval, ansi ); }
-BOOL set_window_pixel_format( HWND hwnd, int format, BOOL internal ) +BOOL set_window_pixel_format( HWND hwnd, int format ) { WND *win = get_win_ptr( hwnd );
@@ -1547,20 +1547,14 @@ BOOL set_window_pixel_format( HWND hwnd, int format, BOOL internal ) WARN( "setting format %d on win %p not supported\n", format, hwnd ); return FALSE; } - if (internal) - win->internal_pixel_format = format; - else - { - win->internal_pixel_format = 0; - win->pixel_format = format; - } + win->pixel_format = format; release_win_ptr( win );
update_window_state( hwnd ); return TRUE; }
-int get_window_pixel_format( HWND hwnd, BOOL internal ) +int get_window_pixel_format( HWND hwnd ) { WND *win = get_win_ptr( hwnd ); int ret; @@ -1571,7 +1565,7 @@ int get_window_pixel_format( HWND hwnd, BOOL internal ) return -1; }
- ret = internal && win->internal_pixel_format ? win->internal_pixel_format : win->pixel_format; + ret = win->pixel_format; release_win_ptr( win );
return ret; @@ -1584,7 +1578,7 @@ static int window_has_client_surface( HWND hwnd ) BOOL ret;
if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS) return FALSE; - ret = win->pixel_format || win->internal_pixel_format; + ret = win->pixel_format || win->current_drawable; release_win_ptr( win ); if (ret) return TRUE;
@@ -2210,7 +2204,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru } if (new_surface) req->paint_flags |= SET_WINPOS_PAINT_SURFACE; if (is_layered) req->paint_flags |= SET_WINPOS_LAYERED_WINDOW; - if (win->pixel_format || win->internal_pixel_format) + if (win->pixel_format || win->current_drawable) req->paint_flags |= SET_WINPOS_PIXEL_FORMAT;
if ((ret = !wine_server_call( req )))
From: Rémi Bernon rbernon@codeweavers.com
Internal pixel format is now fully hidden from applications and local to the context DC.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58846 --- dlls/wined3d/context_gl.c | 42 --------------------------------------- dlls/wined3d/wined3d_gl.h | 2 -- 2 files changed, 44 deletions(-)
diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c index ad2a50a66f1..61bf38cdafc 100644 --- a/dlls/wined3d/context_gl.c +++ b/dlls/wined3d/context_gl.c @@ -1162,38 +1162,6 @@ void wined3d_context_gl_texture_update(struct wined3d_context_gl *context_gl, } }
-static BOOL wined3d_context_gl_restore_pixel_format(struct wined3d_context_gl *context_gl) -{ - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - BOOL ret = FALSE; - - if (context_gl->restore_pf && IsWindow(context_gl->restore_pf_win)) - { - if (gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH]) - { - HDC dc = GetDCEx(context_gl->restore_pf_win, 0, DCX_USESTYLE | DCX_CACHE); - if (dc) - { - if (!(ret = GL_EXTCALL(wglSetPixelFormatWINE(dc, context_gl->restore_pf)))) - { - ERR("Failed to restore pixel format %d on window %p.\n", - context_gl->restore_pf, context_gl->restore_pf_win); - } - ReleaseDC(context_gl->restore_pf_win, dc); - } - } - else - { - ERR("Unable to restore pixel format %d on window %p.\n", - context_gl->restore_pf, context_gl->restore_pf_win); - } - } - - context_gl->restore_pf = 0; - context_gl->restore_pf_win = NULL; - return ret; -} - static BOOL wined3d_context_gl_set_pixel_format(struct wined3d_context_gl *context_gl) { const struct wined3d_gl_info *gl_info = context_gl->gl_info; @@ -1201,7 +1169,6 @@ static BOOL wined3d_context_gl_set_pixel_format(struct wined3d_context_gl *conte int format = context_gl->pixel_format; HDC dc = context_gl->dc; int current; - HWND win;
if (private && context_gl->dc_has_format) return TRUE; @@ -1246,12 +1213,6 @@ static BOOL wined3d_context_gl_set_pixel_format(struct wined3d_context_gl *conte return FALSE; }
- win = private ? NULL : WindowFromDC(dc); - if (win != context_gl->restore_pf_win) - wined3d_context_gl_restore_pixel_format(context_gl); - context_gl->restore_pf = private ? 0 : current; - context_gl->restore_pf_win = win; - success: if (private) context_gl->dc_has_format = TRUE; @@ -1546,7 +1507,6 @@ static void wined3d_context_gl_cleanup(struct wined3d_context_gl *context_gl)
free(context_gl->texture_type);
- wined3d_context_gl_restore_pixel_format(context_gl); if (restore_ctx) context_restore_gl_context(gl_info, restore_dc, restore_ctx); else if (wglGetCurrentContext() && !wglMakeCurrent(NULL, NULL)) @@ -1654,8 +1614,6 @@ void wined3d_context_gl_release(struct wined3d_context_gl *context_gl)
if (!--context_gl->level) { - if (wined3d_context_gl_restore_pixel_format(context_gl)) - context_gl->needs_set = 1; if (context_gl->restore_ctx) { TRACE("Restoring GL context %p on device context %p.\n", context_gl->restore_ctx, context_gl->restore_dc); diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h index 5e35e723958..a3d54fe5c19 100644 --- a/dlls/wined3d/wined3d_gl.h +++ b/dlls/wined3d/wined3d_gl.h @@ -644,8 +644,6 @@ struct wined3d_context_gl unsigned int level; HGLRC restore_ctx; HDC restore_dc; - int restore_pf; - HWND restore_pf_win; HGLRC gl_ctx; HDC dc; int pixel_format;