-- v2: win32u: Don't store the window OpenGL drawables on the DCs. win32u: Keep a separate pointer for unused opengl drawable. win32u: Rename window opengl drawable to current_drawable. win32u: Introduce an context_exchange_drawables helper.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/opengl.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-)
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 3bbf0d4cb93..5f8586f8655 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1303,16 +1303,13 @@ static void win32u_get_pixel_formats( struct wgl_pixel_format *formats, UINT max *num_onscreen_formats = onscreen_count; }
-static void context_set_drawables( struct wgl_context *context, struct opengl_drawable *new_draw, struct opengl_drawable *new_read ) +static void context_exchange_drawables( struct wgl_context *context, struct opengl_drawable **draw, struct opengl_drawable **read ) { struct opengl_drawable *old_draw = context->draw, *old_read = context->read; - - TRACE( "context %p new_draw %s new_read %s\n", context, debugstr_opengl_drawable(new_draw), debugstr_opengl_drawable(new_read) ); - - if ((context->draw = new_draw)) opengl_drawable_add_ref( new_draw ); - if ((context->read = new_read)) opengl_drawable_add_ref( new_read ); - if (old_draw) opengl_drawable_release( old_draw ); - if (old_read) opengl_drawable_release( old_read ); + context->draw = *draw; + context->read = *read; + *draw = old_draw; + *read = old_read; }
static BOOL context_unset_current( struct wgl_context *context ) @@ -1332,8 +1329,8 @@ static BOOL context_unset_current( struct wgl_context *context )
static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, HDC read_hdc ) { + struct opengl_drawable *new_draw, *new_read, *old_draw = NULL, *old_read = NULL; struct wgl_context *previous = NtCurrentTeb()->glContext; - struct opengl_drawable *new_draw, *new_read; BOOL ret = FALSE; HWND hwnd;
@@ -1354,7 +1351,7 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H if (previous == context && new_draw == context->draw && new_read == context->read) ret = TRUE; else if (previous) { - struct opengl_drawable *old_draw = previous->draw, *old_read = previous->read; + context_exchange_drawables( previous, &old_draw, &old_read ); /* take ownership of the previous context drawables */ opengl_drawable_flush( old_read, old_read->interval, GL_FLUSH_WAS_CURRENT ); if (old_read != old_draw) opengl_drawable_flush( old_draw, old_draw->interval, GL_FLUSH_WAS_CURRENT ); } @@ -1362,8 +1359,10 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H if (!ret && (ret = driver_funcs->p_make_current( new_draw, new_read, context->driver_private ))) { NtCurrentTeb()->glContext = context; - context_set_drawables( context, new_draw, new_read ); - if (previous && previous != context) context_set_drawables( previous, NULL, NULL ); + + /* all good, release previous context drawables if any */ + if (old_draw) opengl_drawable_release( old_draw ); + if (old_read) opengl_drawable_release( old_read );
opengl_drawable_flush( new_read, new_read->interval, GL_FLUSH_SET_CURRENT ); if (new_read != new_draw) opengl_drawable_flush( new_draw, new_draw->interval, GL_FLUSH_SET_CURRENT ); @@ -1375,16 +1374,18 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H opengl_drawable_flush( new_draw, new_draw->interval, 0 ); /* update the current window drawable to the last used draw surface */ if ((hwnd = NtUserWindowFromDC( draw_hdc ))) set_window_opengl_drawable( hwnd, new_draw ); + context_exchange_drawables( context, &new_draw, &new_read ); } else if (previous) { - struct opengl_drawable *old_draw = previous->draw, *old_read = previous->read; opengl_drawable_flush( old_read, old_read->interval, GL_FLUSH_SET_CURRENT ); if (old_read != old_draw) opengl_drawable_flush( old_draw, old_draw->interval, GL_FLUSH_SET_CURRENT ); + context_exchange_drawables( previous, &old_draw, &old_read ); /* give back ownership of the previous drawables */ + assert( !old_draw && !old_read ); }
- opengl_drawable_release( new_draw ); - opengl_drawable_release( new_read ); + if (new_draw) opengl_drawable_release( new_draw ); + if (new_read) opengl_drawable_release( new_read ); return ret; }
@@ -1417,10 +1418,16 @@ static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct
if (!context) { + struct opengl_drawable *draw = NULL, *read = NULL; + if (!(context = prev_context)) return TRUE; if (!context_unset_current( context )) return FALSE; NtCurrentTeb()->glContext = NULL; - context_set_drawables( context, NULL, NULL ); + + context_exchange_drawables( context, &draw, &read ); + opengl_drawable_release( draw ); + opengl_drawable_release( read ); + return TRUE; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dce.c | 2 +- dlls/win32u/ntuser_private.h | 2 +- dlls/win32u/opengl.c | 16 ++++++++-------- dlls/win32u/window.c | 8 ++++---- dlls/wineandroid.drv/opengl.c | 2 +- include/wine/opengl_driver.h | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index d1cf5c78bab..142c3c1dc93 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1367,7 +1367,7 @@ HDC WINAPI NtUserGetDCEx( HWND hwnd, HRGN clip_rgn, DWORD flags )
if (dce->hwnd != hwnd) { - struct opengl_drawable *drawable = get_window_opengl_drawable( hwnd ); + struct opengl_drawable *drawable = get_window_current_drawable( hwnd ); set_dc_opengl_drawable( dce->hdc, drawable ); if (drawable) opengl_drawable_release( drawable ); } diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index f5559c5ca4f..25d42f98d4e 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -66,7 +66,7 @@ typedef struct tagWND HICON hIconSmall2; /* window's secondary small icon, derived from hIcon */ HIMC imc; /* window's input context */ struct window_surface *surface; /* Window surface if any */ - struct opengl_drawable *opengl_drawable; /* last GL client surface for this window */ + struct opengl_drawable *current_drawable; /* current GL client surface for this window */ 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 */ diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 5f8586f8655..f4f562087fd 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1103,29 +1103,29 @@ static int win32u_wglGetPixelFormat( HDC hdc )
void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *new_drawable ) { - void *old_drawable = NULL; + struct opengl_drawable *old_drawable = NULL; WND *win;
TRACE( "hwnd %p, new_drawable %s\n", hwnd, debugstr_opengl_drawable( new_drawable ) );
if ((win = get_win_ptr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS) { - old_drawable = win->opengl_drawable; - if ((win->opengl_drawable = new_drawable)) opengl_drawable_add_ref( new_drawable ); + old_drawable = win->current_drawable; + if ((win->current_drawable = new_drawable)) opengl_drawable_add_ref( new_drawable ); release_win_ptr( win ); }
if (old_drawable) opengl_drawable_release( old_drawable ); }
-struct opengl_drawable *get_window_opengl_drawable( HWND hwnd ) +struct opengl_drawable *get_window_current_drawable( HWND hwnd ) { - void *drawable = NULL; + struct opengl_drawable *drawable = NULL; WND *win;
if ((win = get_win_ptr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS) { - if ((drawable = win->opengl_drawable)) opengl_drawable_add_ref( drawable ); + if ((drawable = win->current_drawable)) opengl_drawable_add_ref( drawable ); release_win_ptr( win ); }
@@ -1337,7 +1337,7 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H new_draw = get_dc_opengl_drawable( draw_hdc );
/* get the last used window drawable when reading */ - if ((hwnd = NtUserWindowFromDC( read_hdc ))) new_read = get_window_opengl_drawable( hwnd ); + if ((hwnd = NtUserWindowFromDC( read_hdc ))) new_read = get_window_current_drawable( hwnd ); else new_read = get_dc_opengl_drawable( read_hdc );
TRACE( "context %p, new_draw %s, new_read %s\n", context, debugstr_opengl_drawable( new_draw ), debugstr_opengl_drawable( new_read ) ); @@ -1963,7 +1963,7 @@ static BOOL win32u_wglSwapBuffers( HDC hdc ) if (context) context_sync_drawables( context, draw_hdc, read_hdc );
if (context) opengl_drawable_add_ref( (draw = context->draw) ); - else if (!(draw = get_window_opengl_drawable( hwnd ))) return FALSE; + else if (!(draw = get_window_current_drawable( hwnd ))) return FALSE;
opengl_drawable_flush( draw, interval, 0 ); ret = draw->funcs->swap( draw ); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 4345c7b7ff4..7422a4c3d4a 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -5186,7 +5186,7 @@ LRESULT destroy_window( HWND hwnd ) }
detach_client_surfaces( hwnd ); - if (win->opengl_drawable) opengl_drawable_release( win->opengl_drawable ); + if (win->current_drawable) opengl_drawable_release( win->current_drawable ); user_driver->pDestroyWindow( hwnd );
free_window_handle( hwnd ); @@ -5291,7 +5291,7 @@ void destroy_thread_windows(void) HWND handle; HMENU menu; HMENU sys_menu; - struct opengl_drawable *opengl_drawable; + struct opengl_drawable *current_drawable; struct window_surface *surface; struct destroy_entry *next; } *entry, *free_list = NULL; @@ -5317,7 +5317,7 @@ void destroy_thread_windows(void) tmp.handle = win->handle; if (!is_child) tmp.menu = (HMENU)win->wIDmenu; tmp.sys_menu = win->hSysMenu; - tmp.opengl_drawable = win->opengl_drawable; + tmp.current_drawable = win->current_drawable; tmp.surface = win->surface; *entry = tmp;
@@ -5342,7 +5342,7 @@ void destroy_thread_windows(void)
detach_client_surfaces( entry->handle ); user_driver->pDestroyWindow( entry->handle ); - if (entry->opengl_drawable) opengl_drawable_release( entry->opengl_drawable ); + if (entry->current_drawable) opengl_drawable_release( entry->current_drawable );
NtUserDestroyMenu( entry->menu ); NtUserDestroyMenu( entry->sys_menu ); diff --git a/dlls/wineandroid.drv/opengl.c b/dlls/wineandroid.drv/opengl.c index 4893e288289..f0eb98844e3 100644 --- a/dlls/wineandroid.drv/opengl.c +++ b/dlls/wineandroid.drv/opengl.c @@ -102,7 +102,7 @@ void update_gl_drawable( HWND hwnd ) { struct gl_drawable *old, *new;
- if (!(old = impl_from_opengl_drawable( get_window_opengl_drawable( hwnd ) ))) return; + if (!(old = impl_from_opengl_drawable( get_window_current_drawable( hwnd ) ))) return; if ((new = create_gl_drawable( hwnd, old->base.format, old->window ))) { set_window_opengl_drawable( hwnd, &new->base ); diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index a468e5e0a40..c961e5602be 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -183,7 +183,7 @@ W32KAPI void *opengl_drawable_create( UINT size, const struct opengl_drawable_fu W32KAPI void opengl_drawable_add_ref( struct opengl_drawable *drawable ); W32KAPI void opengl_drawable_release( struct opengl_drawable *drawable );
-W32KAPI struct opengl_drawable *get_window_opengl_drawable( HWND hwnd ); +W32KAPI struct opengl_drawable *get_window_current_drawable( HWND hwnd ); W32KAPI void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *drawable );
/* interface between win32u and the user drivers */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/opengl.c | 56 ++++++++++++++++++++++++++++------- dlls/win32u/window.c | 4 +++ dlls/wineandroid.drv/opengl.c | 13 ++------ include/wine/opengl_driver.h | 2 +- 5 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 25d42f98d4e..ccf4a75c2d9 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -67,6 +67,7 @@ typedef struct tagWND HIMC imc; /* window's input context */ struct window_surface *surface; /* Window surface if any */ struct opengl_drawable *current_drawable; /* current GL client surface for this window */ + struct opengl_drawable *unused_drawable; /* unused GL client surface for this window */ 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 */ diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index f4f562087fd..003435250be 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1101,7 +1101,7 @@ static int win32u_wglGetPixelFormat( HDC hdc ) return format > 0 ? format : 0; }
-void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *new_drawable ) +void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *new_drawable, BOOL current ) { struct opengl_drawable *old_drawable = NULL; WND *win; @@ -1110,8 +1110,9 @@ void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *new_drawable
if ((win = get_win_ptr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS) { - old_drawable = win->current_drawable; - if ((win->current_drawable = new_drawable)) opengl_drawable_add_ref( new_drawable ); + struct opengl_drawable **ptr = current ? &win->current_drawable : &win->unused_drawable; + old_drawable = *ptr; + if ((*ptr = new_drawable)) opengl_drawable_add_ref( new_drawable ); release_win_ptr( win ); }
@@ -1133,6 +1134,35 @@ struct opengl_drawable *get_window_current_drawable( HWND hwnd ) return drawable; }
+static struct opengl_drawable *get_window_unused_drawable( HWND hwnd, int format ) +{ + struct opengl_drawable *drawable = NULL; + WND *win; + + if ((win = get_win_ptr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS) + { + drawable = win->unused_drawable; + win->unused_drawable = NULL; + release_win_ptr( win ); + } + + if (drawable && drawable->format != format) + { + opengl_drawable_release( drawable ); + drawable = NULL; + } + + /* No compatible window drawable found, try creating a new one. This is not what native + * is doing, it allows multiple contexts to be current on separate threads on the same + * window, each drawing to the same back/front buffers. We cannot do that because host + * OpenGL usually doesn't allow multiple contexts to use the same surface at the same time. + */ + if (!drawable) driver_funcs->p_surface_create( hwnd, format, &drawable ); + + TRACE( "hwnd %p, drawable %s\n", hwnd, debugstr_opengl_drawable( drawable ) ); + return drawable; +} + void set_dc_opengl_drawable( HDC hdc, struct opengl_drawable *new_drawable ) { void *old_drawable = NULL; @@ -1247,7 +1277,6 @@ static BOOL set_dc_pixel_format( HDC hdc, int new_format, BOOL internal ) { struct opengl_drawable *drawable; int old_format; - BOOL ret;
if (new_format > onscreen) { @@ -1259,16 +1288,14 @@ static BOOL set_dc_pixel_format( HDC hdc, int new_format, BOOL internal )
if ((old_format = get_window_pixel_format( hwnd, FALSE )) && !internal) return old_format == new_format;
- drawable = get_dc_opengl_drawable( hdc ); - if ((ret = driver_funcs->p_surface_create( hwnd, new_format, &drawable ))) + if ((drawable = get_window_unused_drawable( hwnd, new_format ))) { - /* update the current window drawable to the last used draw surface */ - if ((hwnd = NtUserWindowFromDC( hdc ))) set_window_opengl_drawable( hwnd, drawable ); set_dc_opengl_drawable( hdc, drawable ); + set_window_opengl_drawable( hwnd, drawable, TRUE ); + set_window_opengl_drawable( hwnd, drawable, FALSE ); + opengl_drawable_release( drawable ); } - if (drawable) opengl_drawable_release( drawable );
- if (!ret) return FALSE; return set_window_pixel_format( hwnd, new_format, internal ); }
@@ -1360,6 +1387,11 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H { NtCurrentTeb()->glContext = context;
+ if (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) + set_window_opengl_drawable( old_read->client->hwnd, old_read, FALSE ); + /* all good, release previous context drawables if any */ if (old_draw) opengl_drawable_release( old_draw ); if (old_read) opengl_drawable_release( old_read ); @@ -1373,7 +1405,7 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H opengl_drawable_flush( new_read, new_read->interval, 0 ); opengl_drawable_flush( new_draw, new_draw->interval, 0 ); /* update the current window drawable to the last used draw surface */ - if ((hwnd = NtUserWindowFromDC( draw_hdc ))) set_window_opengl_drawable( hwnd, new_draw ); + if ((hwnd = NtUserWindowFromDC( draw_hdc ))) set_window_opengl_drawable( hwnd, new_draw, TRUE ); context_exchange_drawables( context, &new_draw, &new_read ); } else if (previous) @@ -1425,7 +1457,9 @@ static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct NtCurrentTeb()->glContext = NULL;
context_exchange_drawables( context, &draw, &read ); + if (draw->client) set_window_opengl_drawable( draw->client->hwnd, draw, FALSE ); opengl_drawable_release( draw ); + if (read->client) set_window_opengl_drawable( read->client->hwnd, read, FALSE ); opengl_drawable_release( read );
return TRUE; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 7422a4c3d4a..f91ab2bfcef 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -5187,6 +5187,7 @@ LRESULT destroy_window( HWND hwnd )
detach_client_surfaces( hwnd ); if (win->current_drawable) opengl_drawable_release( win->current_drawable ); + if (win->unused_drawable) opengl_drawable_release( win->unused_drawable ); user_driver->pDestroyWindow( hwnd );
free_window_handle( hwnd ); @@ -5292,6 +5293,7 @@ void destroy_thread_windows(void) HMENU menu; HMENU sys_menu; struct opengl_drawable *current_drawable; + struct opengl_drawable *unused_drawable; struct window_surface *surface; struct destroy_entry *next; } *entry, *free_list = NULL; @@ -5318,6 +5320,7 @@ void destroy_thread_windows(void) if (!is_child) tmp.menu = (HMENU)win->wIDmenu; tmp.sys_menu = win->hSysMenu; tmp.current_drawable = win->current_drawable; + tmp.unused_drawable = win->unused_drawable; tmp.surface = win->surface; *entry = tmp;
@@ -5343,6 +5346,7 @@ void destroy_thread_windows(void) detach_client_surfaces( entry->handle ); user_driver->pDestroyWindow( entry->handle ); if (entry->current_drawable) opengl_drawable_release( entry->current_drawable ); + if (entry->unused_drawable) opengl_drawable_release( entry->unused_drawable );
NtUserDestroyMenu( entry->menu ); NtUserDestroyMenu( entry->sys_menu ); diff --git a/dlls/wineandroid.drv/opengl.c b/dlls/wineandroid.drv/opengl.c index f0eb98844e3..2345d98e5ba 100644 --- a/dlls/wineandroid.drv/opengl.c +++ b/dlls/wineandroid.drv/opengl.c @@ -100,16 +100,9 @@ static void android_drawable_destroy( struct opengl_drawable *base )
void update_gl_drawable( HWND hwnd ) { - struct gl_drawable *old, *new; - - if (!(old = impl_from_opengl_drawable( get_window_current_drawable( hwnd ) ))) return; - if ((new = create_gl_drawable( hwnd, old->base.format, old->window ))) - { - set_window_opengl_drawable( hwnd, &new->base ); - opengl_drawable_release( &new->base ); - } - opengl_drawable_release( &old->base ); - + /* clear any cached opengl drawable */ + set_window_opengl_drawable( hwnd, NULL, TRUE ); + set_window_opengl_drawable( hwnd, NULL, FALSE ); NtUserRedrawWindow( hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE ); }
diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index c961e5602be..ed3e09d3cc5 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -184,7 +184,7 @@ W32KAPI void opengl_drawable_add_ref( struct opengl_drawable *drawable ); W32KAPI void opengl_drawable_release( struct opengl_drawable *drawable );
W32KAPI struct opengl_drawable *get_window_current_drawable( HWND hwnd ); -W32KAPI void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *drawable ); +W32KAPI void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *drawable, BOOL current );
/* interface between win32u and the user drivers */ struct opengl_driver_funcs
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/opengl32/tests/opengl.c | 76 ++++++++++++++++++------------------ dlls/win32u/dce.c | 8 ---- dlls/win32u/opengl.c | 56 ++++++++++++++++---------- dlls/win32u/win32u_private.h | 5 --- include/wine/opengl_driver.h | 1 - 5 files changed, 74 insertions(+), 72 deletions(-)
diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index 0131a68e3d8..55125722297 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -2552,27 +2552,27 @@ static DWORD CALLBACK test_window_dc_thread( void *arg )
ctx = wglCreateContext( hdc ); ok( ctx != NULL, "got %p\n", ctx ); - todo_wine ok_ret( TRUE, wglMakeCurrent( hdc, ctx ) ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( TRUE, wglMakeCurrent( hdc, ctx ) ); + ok_ret( GL_NO_ERROR, glGetError() ); glReadBuffer( GL_BACK ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() );
pixel = 0xdeadbeef; glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); todo_wine ok( pixel == 0xff0000ff, "got %#x\n", pixel ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() );
glClearColor( 0.0, 1.0, 0.0, 1.0 ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() ); glClear( GL_COLOR_BUFFER_BIT ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() );
pixel = 0xdeadbeef; glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( pixel == 0xff00ff00, "got %#x\n", pixel ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok( pixel == 0xff00ff00, "got %#x\n", pixel ); + ok_ret( GL_NO_ERROR, glGetError() );
- todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); + ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); ok_ret( TRUE, wglDeleteContext( ctx ) );
ReleaseDC( hwnd, hdc ); @@ -2652,45 +2652,45 @@ static void test_window_dc(void) dc = GetWindowDC( window ); ctx = wglCreateContext( dc ); ok( ctx != NULL, "got %p\n", ctx ); - todo_wine ok_ret( TRUE, wglMakeCurrent( dc, ctx ) ); + ok_ret( TRUE, wglMakeCurrent( dc, ctx ) ); glReadBuffer( GL_BACK ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() );
glClearColor( 1.0, 0.0, 0.0, 1.0 ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() ); glClear( GL_COLOR_BUFFER_BIT ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() );
pixel = 0xdeadbeef; glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( pixel == 0xff0000ff, "got %#x\n", pixel ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok( pixel == 0xff0000ff, "got %#x\n", pixel ); + ok_ret( GL_NO_ERROR, glGetError() );
ReleaseDC( window, dc );
pixel = 0xdeadbeef; glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( pixel == 0xff0000ff, "got %#x\n", pixel ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok( pixel == 0xff0000ff, "got %#x\n", pixel ); + ok_ret( GL_NO_ERROR, glGetError() );
glFlush(); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() );
pixel = 0xdeadbeef; glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( pixel == 0xff0000ff, "got %#x\n", pixel ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok( pixel == 0xff0000ff, "got %#x\n", pixel ); + ok_ret( GL_NO_ERROR, glGetError() );
dc = GetWindowDC( window ); ok( dc != NULL, "got %p\n", dc ); - todo_wine ok_ret( TRUE, wglMakeCurrent( dc, ctx ) ); + ok_ret( TRUE, wglMakeCurrent( dc, ctx ) );
pixel = 0xdeadbeef; glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( pixel == 0xff0000ff, "got %#x\n", pixel ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok( pixel == 0xff0000ff, "got %#x\n", pixel ); + ok_ret( GL_NO_ERROR, glGetError() );
thread = CreateThread( NULL, 0, test_window_dc_thread, window, 0, NULL ); ok( thread != NULL, "got %p\n", thread ); @@ -2700,32 +2700,32 @@ static void test_window_dc(void) pixel = 0xdeadbeef; glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); todo_wine ok( pixel == 0xff00ff00, "got %#x\n", pixel ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() );
dc1 = GetWindowDC( window ); ok( dc1 != NULL, "got %p\n", dc1 ); - todo_wine ok_ret( TRUE, wglMakeCurrent( dc1, ctx ) ); + ok_ret( TRUE, wglMakeCurrent( dc1, ctx ) );
pixel = 0xdeadbeef; glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); todo_wine ok( pixel == 0xff00ff00, "got %#x\n", pixel ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() );
ctx1 = wglCreateContext( dc1 ); ok( ctx1 != NULL, "got %p\n", ctx1 ); - todo_wine ok_ret( TRUE, wglMakeCurrent( dc1, ctx1 ) ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( TRUE, wglMakeCurrent( dc1, ctx1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); glReadBuffer( GL_BACK ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() );
pixel = 0xdeadbeef; glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( pixel == 0xff00ff00, "got %#x\n", pixel ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok( pixel == 0xff00ff00, "got %#x\n", pixel ); + ok_ret( GL_NO_ERROR, glGetError() );
- todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); + ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); ok_ret( TRUE, wglDeleteContext( ctx1 ) ); ReleaseDC( window, dc1 );
@@ -2737,17 +2737,17 @@ static void test_window_dc(void) ok( dc != NULL, "got %p\n", dc ); ctx = wglCreateContext( dc ); ok( ctx != NULL, "got %p\n", ctx ); - todo_wine ok_ret( TRUE, wglMakeCurrent( dc, ctx ) ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( TRUE, wglMakeCurrent( dc, ctx ) ); + ok_ret( GL_NO_ERROR, glGetError() ); glReadBuffer( GL_BACK ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() );
pixel = 0xdeadbeef; glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( pixel == 0xff00ff00, "got %#x\n", pixel ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok( pixel == 0xff00ff00, "got %#x\n", pixel ); + ok_ret( GL_NO_ERROR, glGetError() );
- todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); + ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); ok_ret( TRUE, wglDeleteContext( ctx ) ); ok_ret( TRUE, SwapBuffers( dc ) ); ReleaseDC( window, dc ); diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 142c3c1dc93..1eb966d3fca 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -886,7 +886,6 @@ static void release_dce( struct dce *dce )
set_visible_region( dce->hdc, 0, &dummy_surface.rect, &dummy_surface.rect, &dummy_surface ); user_driver->pReleaseDC( dce->hwnd, dce->hdc ); - set_dc_opengl_drawable( dce->hdc, NULL );
if (dce->clip_rgn) NtGdiDeleteObjectApp( dce->clip_rgn ); dce->clip_rgn = 0; @@ -1224,7 +1223,6 @@ static INT release_dc( HWND hwnd, HDC hdc, BOOL end_paint ) if (end_paint || (dce->flags & DCX_CACHE)) delete_clip_rgn( dce ); if (dce->flags & DCX_CACHE) { - set_dc_opengl_drawable( dce->hdc, NULL ); dce->count = 0; set_dce_flags( dce->hdc, DCHF_DISABLEDC ); } @@ -1365,12 +1363,6 @@ HDC WINAPI NtUserGetDCEx( HWND hwnd, HRGN clip_rgn, DWORD flags ) if (get_window_long( hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) NtGdiSetLayout( dce->hdc, -1, LAYOUT_RTL );
- if (dce->hwnd != hwnd) - { - struct opengl_drawable *drawable = get_window_current_drawable( hwnd ); - set_dc_opengl_drawable( dce->hdc, drawable ); - if (drawable) opengl_drawable_release( drawable ); - } dce->hwnd = hwnd; dce->flags = (dce->flags & ~user_flags) | (flags & user_flags);
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 003435250be..57e0aa0e27c 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1119,7 +1119,7 @@ void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *new_drawable if (old_drawable) opengl_drawable_release( old_drawable ); }
-struct opengl_drawable *get_window_current_drawable( HWND hwnd ) +static struct opengl_drawable *get_window_current_drawable( HWND hwnd ) { struct opengl_drawable *drawable = NULL; WND *win; @@ -1163,7 +1163,7 @@ static struct opengl_drawable *get_window_unused_drawable( HWND hwnd, int format return drawable; }
-void set_dc_opengl_drawable( HDC hdc, struct opengl_drawable *new_drawable ) +static void set_dc_opengl_drawable( HDC hdc, struct opengl_drawable *new_drawable ) { void *old_drawable = NULL; DC *dc; @@ -1290,7 +1290,6 @@ static BOOL set_dc_pixel_format( HDC hdc, int new_format, BOOL internal )
if ((drawable = get_window_unused_drawable( hwnd, new_format ))) { - set_dc_opengl_drawable( hdc, drawable ); set_window_opengl_drawable( hwnd, drawable, TRUE ); set_window_opengl_drawable( hwnd, drawable, FALSE ); opengl_drawable_release( drawable ); @@ -1354,18 +1353,38 @@ static BOOL context_unset_current( struct wgl_context *context ) return FALSE; }
+/* 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 ) +{ + struct opengl_drawable *current; + HWND hwnd = NULL; + + if (hdc && !(hwnd = NtUserWindowFromDC( hdc ))) return get_dc_opengl_drawable( hdc ); + if (!hdc && drawable && drawable->client) hwnd = drawable->client->hwnd; + if (!hwnd) return NULL; + + /* if the window still has a drawable, keep using the one we have */ + if (drawable && (current = get_window_current_drawable( hwnd ))) + { + opengl_drawable_release( current ); + opengl_drawable_add_ref( drawable ); + return drawable; + } + + /* get an updated drawable with the desired format */ + return get_window_unused_drawable( hwnd, format ); +} + static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, HDC read_hdc ) { struct opengl_drawable *new_draw, *new_read, *old_draw = NULL, *old_read = NULL; struct wgl_context *previous = NtCurrentTeb()->glContext; BOOL ret = FALSE; - HWND hwnd; - - new_draw = get_dc_opengl_drawable( draw_hdc );
- /* get the last used window drawable when reading */ - if ((hwnd = NtUserWindowFromDC( read_hdc ))) new_read = get_window_current_drawable( hwnd ); - else new_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) ); + else new_read = get_updated_drawable( read_hdc, context->format, context->read );
TRACE( "context %p, new_draw %s, new_read %s\n", context, debugstr_opengl_drawable( new_draw ), debugstr_opengl_drawable( new_read ) );
@@ -1405,7 +1424,7 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H opengl_drawable_flush( new_read, new_read->interval, 0 ); opengl_drawable_flush( new_draw, new_draw->interval, 0 ); /* update the current window drawable to the last used draw surface */ - if ((hwnd = NtUserWindowFromDC( draw_hdc ))) set_window_opengl_drawable( hwnd, new_draw, TRUE ); + if (new_draw->client) set_window_opengl_drawable( new_draw->client->hwnd, new_draw, TRUE ); context_exchange_drawables( context, &new_draw, &new_read ); } else if (previous) @@ -1957,19 +1976,17 @@ static BOOL flush_memory_pbuffer( void (*flush)(void) )
static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush)(void) ) { - HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1]; const struct opengl_funcs *funcs = &display_funcs; + struct opengl_drawable *draw = context->draw; UINT flags = 0; int interval; - HWND hwnd;
- if (!(hwnd = NtUserWindowFromDC( draw_hdc ))) return flush_memory_pbuffer( flush ); + if (!draw->client) return flush_memory_pbuffer( flush ); + interval = get_window_swap_interval( draw->client->hwnd );
- interval = get_window_swap_interval( hwnd ); - - TRACE( "context %p, hwnd %p, draw_hdc %p, interval %d, flush %p\n", context, hwnd, draw_hdc, interval, flush ); + TRACE( "context %p, hwnd %p, interval %d, flush %p\n", context, draw->client->hwnd, interval, flush );
- context_sync_drawables( context, draw_hdc, read_hdc ); + context_sync_drawables( context, 0, 0 );
if (flush) flush(); if (flush == funcs->p_glFinish) flags |= GL_FLUSH_FINISHED; @@ -1980,7 +1997,6 @@ static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush)
static BOOL win32u_wglSwapBuffers( HDC hdc ) { - HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1]; struct wgl_context *context = NtCurrentTeb()->glContext; const struct opengl_funcs *funcs = &display_funcs; struct opengl_drawable *draw; @@ -1992,9 +2008,9 @@ static BOOL win32u_wglSwapBuffers( HDC hdc )
interval = get_window_swap_interval( hwnd );
- TRACE( "context %p, hwnd %p, draw_hdc %p, interval %d\n", context, hwnd, draw_hdc, interval ); + TRACE( "context %p, hwnd %p, hdc %p, interval %d\n", context, hwnd, hdc, interval );
- if (context) context_sync_drawables( context, draw_hdc, read_hdc ); + if (context) context_sync_drawables( context, 0, 0 );
if (context) opengl_drawable_add_ref( (draw = context->draw) ); else if (!(draw = get_window_current_drawable( hwnd ))) return FALSE; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 4c7ce21d5b4..5db351836de 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -189,11 +189,6 @@ extern void user_lock(void); extern void user_unlock(void); extern void user_check_not_lock(void);
-/* opengl.c */ - -struct opengl_drawable; -extern void set_dc_opengl_drawable( HDC hdc, struct opengl_drawable *new_drawable ); - /* d3dkmtc. */
struct vulkan_gpu diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index ed3e09d3cc5..38b14f57e3b 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -183,7 +183,6 @@ W32KAPI void *opengl_drawable_create( UINT size, const struct opengl_drawable_fu W32KAPI void opengl_drawable_add_ref( struct opengl_drawable *drawable ); W32KAPI void opengl_drawable_release( struct opengl_drawable *drawable );
-W32KAPI struct opengl_drawable *get_window_current_drawable( HWND hwnd ); W32KAPI void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *drawable, BOOL current );
/* interface between win32u and the user drivers */