[PATCH v2 0/3] MR10190: winu32: Try harder to replace the old drawable everywhere.
-- v2: win32u: Also try to use DC own drawable in get_updated_drawable() when context is flushed. win32u: Do not keep old drawable as window unused if it was replaced. opengl32: Don't access drawable after wgl_context_flush() in flush_context(). https://gitlab.winehq.org/wine/wine/-/merge_requests/10190
From: Paul Gofman <pgofman@codeweavers.com> wgl_context_flush() may recreate the drawable and release the old one. --- dlls/opengl32/unix_wgl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 6d73b1cd735..1d0c995e7fe 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -1376,6 +1376,7 @@ static void flush_context( TEB *teb, void (*flush)(void) ) { struct opengl_drawable *read, *draw; struct context *ctx = get_current_context( teb, &read, &draw ); + HWND draw_hwnd = ctx && draw && draw->client ? draw->client->hwnd : NULL; const struct opengl_funcs *funcs = teb->glTable; UINT flags = 0; @@ -1395,7 +1396,7 @@ static void flush_context( TEB *teb, void (*flush)(void) ) WARN( "Front buffer rendering emulation, copying front buffer back\n" ); - NtUserGetClientRect( draw->client->hwnd, &rect, NtUserGetDpiForWindow( draw->client->hwnd ) ); + NtUserGetClientRect( draw_hwnd, &rect, NtUserGetDpiForWindow( draw_hwnd ) ); if (ctx->read_fbo) funcs->p_glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 ); funcs->p_glReadBuffer( GL_FRONT_LEFT ); funcs->p_glBlitFramebuffer( 0, 0, rect.right, rect.bottom, 0, 0, rect.right, rect.bottom, mask, GL_NEAREST ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10190
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/win32u/opengl.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 486c3f45c2a..3617712a4ae 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1789,10 +1789,13 @@ static BOOL context_unset_current( struct opengl_context *context ) } /* return an updated drawable, recreating one if the window drawables have been invalidated (mostly wineandroid) */ -static struct opengl_drawable *get_updated_drawable( HDC hdc, int format, struct opengl_drawable *drawable ) +static struct opengl_drawable *get_updated_drawable( HDC hdc, int format, struct opengl_drawable *drawable, + BOOL *updated ) { HWND hwnd = NULL; + *updated = FALSE; + /* return the memory DCs drawables directly */ if (hdc && !(hwnd = NtUserWindowFromDC( hdc ))) return get_dc_opengl_drawable( hdc ); if (!hdc && drawable && drawable->client) hwnd = drawable->client->hwnd; @@ -1809,6 +1812,7 @@ static struct opengl_drawable *get_updated_drawable( HDC hdc, int format, struct if (hdc && (drawable = get_dc_opengl_drawable( hdc ))) return drawable; /* get an updated drawable with the desired format */ + *updated = TRUE; return get_window_unused_drawable( hwnd, format ); } @@ -1816,12 +1820,13 @@ static BOOL context_sync_drawables( struct opengl_context *context, HDC draw_hdc { struct opengl_drawable *new_draw, *new_read, *old_draw = NULL, *old_read = NULL; struct opengl_context *previous = NtCurrentTeb()->glContext; - BOOL ret = FALSE; + BOOL ret = FALSE, draw_updated, read_updated; - if (!(new_draw = get_updated_drawable( draw_hdc, context->format, context->draw ))) return FALSE; + if (!(new_draw = get_updated_drawable( draw_hdc, context->format, context->draw, &draw_updated ))) return FALSE; + read_updated = draw_updated; 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) ); - else new_read = get_updated_drawable( read_hdc, context->format, context->read ); + else new_read = get_updated_drawable( read_hdc, context->format, context->read, &read_updated ); TRACE( "context %p, new_draw %s, new_read %s\n", context, debugstr_opengl_drawable( new_draw ), debugstr_opengl_drawable( new_read ) ); @@ -1843,9 +1848,9 @@ static BOOL context_sync_drawables( struct opengl_context *context, HDC draw_hdc { NtCurrentTeb()->glContext = context; - if (old_draw && old_draw != new_draw && old_draw != new_read && old_draw->client) + if (!draw_updated && old_draw && old_draw != new_draw && old_draw != new_read && old_draw->client) set_window_opengl_drawable( old_draw->client->hwnd, old_draw, FALSE ); - if (old_read && old_read != new_draw && old_read != new_read && old_read->client) + if (!read_updated && old_read && old_read != new_draw && old_read != new_read && old_read->client) set_window_opengl_drawable( old_read->client->hwnd, old_read, FALSE ); /* all good, release previous context drawables if any */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10190
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/win32u/opengl.c | 10 ++++++++-- include/wine/opengl_driver.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 3617712a4ae..ff8e40666bc 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1429,7 +1429,7 @@ static struct opengl_drawable *get_window_unused_drawable( HWND hwnd, int format static void set_dc_opengl_drawable( HDC hdc, struct opengl_drawable *new_drawable ) { - void *old_drawable = NULL; + struct opengl_drawable *old_drawable = NULL; DC *dc; TRACE( "hdc %p, new_drawable %s\n", hdc, debugstr_opengl_drawable( new_drawable ) ); @@ -1437,7 +1437,12 @@ static void set_dc_opengl_drawable( HDC hdc, struct opengl_drawable *new_drawabl if ((dc = get_dc_ptr( hdc ))) { old_drawable = dc->opengl_drawable; - if ((dc->opengl_drawable = new_drawable)) opengl_drawable_add_ref( new_drawable ); + if ((dc->opengl_drawable = new_drawable)) + { + new_drawable->owner_hdc = hdc; + opengl_drawable_add_ref( new_drawable ); + } + if (old_drawable) old_drawable->owner_hdc = 0; release_dc_ptr( dc ); } @@ -1809,6 +1814,7 @@ static struct opengl_drawable *get_updated_drawable( HDC hdc, int format, struct } /* retrieve D3D internal drawables from the DCs if they have any */ + if (!hdc && drawable) hdc = drawable->owner_hdc; if (hdc && (drawable = get_dc_opengl_drawable( hdc ))) return drawable; /* get an updated drawable with the desired format */ diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index 470850c9d49..7b2cea0a87b 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -191,6 +191,7 @@ struct opengl_drawable LONG ref; /* reference count */ struct list entry; /* entry in cleanup lists */ struct client_surface *client; /* underlying client surface */ + HDC owner_hdc; /* HDC owning the drawable, if any (for pbuffer / D3D swapchains) */ int format; /* pixel format of the drawable */ int interval; /* last set surface swap interval */ BOOL doublebuffer; /* pixel format is double buffered */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10190
v2: - Fetch draw-\>client-\>hwnd earlier instead of re-getting drawables in opengl32 (and split that change into a separate patch); - avoid setting old drawable as unused if it was replaced (instead of wrongly putting new drawable there); - track owner DC in the drawable and use that one to properly use owning DC's drawable when get_updated_drawable() is called from flushed context and context / drawables are not switched. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10190#note_130620
participants (2)
-
Paul Gofman -
Paul Gofman (@gofman)