From: Rémi Bernon rbernon@codeweavers.com
--- dlls/opengl32/tests/opengl.c | 188 ++++++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 3 deletions(-)
diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index ea88a50c49f..6f73e36732c 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -36,6 +36,28 @@
#define MAX_FORMATS 256
+static const char *debugstr_ok( const char *cond ) +{ + int c, n = 0; + /* skip possible casts */ + while ((c = *cond++)) + { + if (c == '(') n++; + if (!n) break; + if (c == ')') n--; + } + if (!strchr( cond - 1, '(' )) return wine_dbg_sprintf( "got %s", cond - 1 ); + return wine_dbg_sprintf( "%.*s returned", (int)strcspn( cond - 1, "( " ), cond - 1 ); +} + +#define ok_ex( r, op, e, t, f, ... ) \ + do \ + { \ + t v = (r); \ + ok( v op (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \ + } while (0) +#define ok_ret( e, r ) ok_ex( r, ==, e, UINT, "%#x" ) + static NTSTATUS (WINAPI *pD3DKMTCreateDCFromMemory)( D3DKMT_CREATEDCFROMMEMORY *desc ); static NTSTATUS (WINAPI *pD3DKMTDestroyDCFromMemory)( const D3DKMT_DESTROYDCFROMMEMORY *desc );
@@ -2504,6 +2526,59 @@ static void test_framebuffer(void) DestroyWindow(window); }
+static DWORD CALLBACK test_window_dc_thread( void *arg ) +{ + PIXELFORMATDESCRIPTOR pfd = + { + .nSize = sizeof(pfd), + .nVersion = 1, + .dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + .iPixelType = PFD_TYPE_RGBA, + .cColorBits = 24, + .cDepthBits = 32, + }; + HWND hwnd = arg; + UINT ret, pixel; + HGLRC ctx; + int format; + HDC hdc; + + hdc = GetWindowDC( hwnd ); + ok( hdc != NULL, "got %p\n", hdc ); + format = ChoosePixelFormat( hdc, &pfd ); + ok( format != 0, "got %d\n", format ); + ret = SetPixelFormat( hdc, format, &pfd ); + ok( ret != 0, "got %u\n", ret ); + + 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() ); + glReadBuffer( GL_BACK ); + todo_wine 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() ); + + glClearColor( 0.0, 1.0, 0.0, 1.0 ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + glClear( GL_COLOR_BUFFER_BIT ); + todo_wine 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() ); + + todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); + ok_ret( TRUE, wglDeleteContext( ctx ) ); + + ReleaseDC( hwnd, hdc ); + return 0; +} + static void test_window_dc(void) { PIXELFORMATDESCRIPTOR pf_desc = @@ -2528,9 +2603,11 @@ static void test_window_dc(void) int pixel_format; HWND window; RECT vp, r; - HGLRC ctx; + HGLRC ctx, ctx1; BOOL ret; - HDC dc; + HDC dc, dc1; + UINT pixel; + HANDLE thread;
window = CreateWindowA("static", "opengl32_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0); @@ -2569,7 +2646,112 @@ static void test_window_dc(void) ret = wglDeleteContext(ctx); ok(ret, "Failed to delete GL context, last error %#lx.\n", GetLastError());
- ReleaseDC(window, dc); + ReleaseDC( window, dc ); + + + dc = GetWindowDC( window ); + ctx = wglCreateContext( dc ); + ok( ctx != NULL, "got %p\n", ctx ); + todo_wine ok_ret( TRUE, wglMakeCurrent( dc, ctx ) ); + glReadBuffer( GL_BACK ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + glClearColor( 1.0, 0.0, 0.0, 1.0 ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + glClear( GL_COLOR_BUFFER_BIT ); + todo_wine 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() ); + + 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() ); + + glFlush(); + todo_wine 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() ); + + + dc = GetWindowDC( window ); + ok( dc != NULL, "got %p\n", dc ); + todo_wine 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() ); + + thread = CreateThread( NULL, 0, test_window_dc_thread, window, 0, NULL ); + ok( thread != NULL, "got %p\n", thread ); + ret = WaitForSingleObject( thread, 5000 ); + ok( ret == 0, "got %#x\n", ret ); + + 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() ); + + + dc1 = GetWindowDC( window ); + ok( dc1 != NULL, "got %p\n", dc1 ); + todo_wine 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() ); + + + 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() ); + glReadBuffer( GL_BACK ); + todo_wine 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() ); + + todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); + ok_ret( TRUE, wglDeleteContext( ctx1 ) ); + ReleaseDC( window, dc1 ); + + ok_ret( TRUE, wglDeleteContext( ctx ) ); + ReleaseDC( window, dc ); + + + dc = GetWindowDC( window ); + 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() ); + glReadBuffer( GL_BACK ); + todo_wine 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() ); + + todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); + ok_ret( TRUE, wglDeleteContext( ctx ) ); + todo_wine ok_ret( TRUE, SwapBuffers( dc ) ); + ReleaseDC( window, dc ); + DestroyWindow(window); }
From: Rémi Bernon rbernon@codeweavers.com
--- include/wine/opengl_driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index 984861f106d..a468e5e0a40 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -176,7 +176,7 @@ struct opengl_drawable static inline const char *debugstr_opengl_drawable( struct opengl_drawable *drawable ) { if (!drawable) return "(null)"; - return wine_dbg_sprintf( "%s/%p (format %u)", debugstr_client_surface( drawable->surface ), drawable, drawable->format ); + return wine_dbg_sprintf( "%s/%p (format %u)", debugstr_client_surface( drawable->client ), drawable, drawable->format ); }
W32KAPI void *opengl_drawable_create( UINT size, const struct opengl_drawable_funcs *funcs, int format, struct client_surface *client );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/opengl.c | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-)
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 1a5067c62e1..ba89eb36d23 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1165,12 +1165,13 @@ static struct opengl_drawable *get_dc_opengl_drawable( HDC hdc ) return drawable; }
-static BOOL create_memory_pbuffer( HDC hdc, int format ) +static BOOL create_memory_pbuffer( HDC hdc ) { const struct opengl_funcs *funcs = &display_funcs; dib_info dib = {.rect = {0, 0, 1, 1}}; BOOL ret = TRUE; BITMAPOBJ *bmp; + int format = 0; DC *dc;
if (!(dc = get_dc_ptr( hdc ))) return FALSE; @@ -1178,12 +1179,13 @@ static BOOL create_memory_pbuffer( HDC hdc, int format ) else if (get_gdi_object_type( hdc ) != NTGDI_OBJ_MEMDC) ret = FALSE; else if ((bmp = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP ))) { + if (!(format = dc->pixel_format)) ret = FALSE; init_dib_info_from_bitmapobj( &dib, bmp ); GDI_ReleaseObj( dc->hBitmap ); } release_dc_ptr( dc );
- if (ret && format) + if (ret) { int width = dib.rect.right - dib.rect.left, height = dib.rect.bottom - dib.rect.top; struct wgl_pbuffer *pbuffer; @@ -1332,10 +1334,9 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H { struct wgl_context *previous = NtCurrentTeb()->glContext; struct opengl_drawable *new_draw, *new_read; - BOOL ret = FALSE, flush; + BOOL ret = FALSE; HWND hwnd;
- flush = create_memory_pbuffer( draw_hdc, context->format ); new_draw = get_dc_opengl_drawable( draw_hdc );
/* get the last used window drawable when reading */ @@ -1374,7 +1375,6 @@ 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 ); - if (flush) flush_memory_dc( context, draw_hdc, TRUE, NULL ); } else if (previous) { @@ -1410,6 +1410,7 @@ static void pop_internal_context( struct wgl_context *context ) static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct wgl_context *context ) { struct wgl_context *prev_context = NtCurrentTeb()->glContext; + BOOL created; int format;
TRACE( "draw_hdc %p, read_hdc %p, context %p\n", draw_hdc, read_hdc, context ); @@ -1436,8 +1437,11 @@ static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct return FALSE; }
+ created = create_memory_pbuffer( draw_hdc ); if (!context_sync_drawables( context, draw_hdc, read_hdc )) return FALSE; NtCurrentTeb()->glContext = context; + if (created) flush_memory_dc( context, draw_hdc, TRUE, NULL ); + return TRUE; }
@@ -1896,6 +1900,20 @@ static BOOL win32u_wgl_context_reset( struct wgl_context *context, HDC hdc, stru return TRUE; }
+static BOOL flush_memory_pbuffer( void (*flush)(void) ) +{ + HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1]; + struct wgl_context *context = NtCurrentTeb()->glContext; + BOOL created; + + TRACE( "context %p, draw_hdc %p, read_hdc %p, flush %p\n", context, draw_hdc, read_hdc, flush ); + + created = create_memory_pbuffer( draw_hdc ); + if (context) context_sync_drawables( context, draw_hdc, read_hdc ); + if (created) flush_memory_dc( context, draw_hdc, TRUE, NULL ); + return flush_memory_dc( context, draw_hdc, FALSE, flush ); +} + static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush)(void) ) { HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1]; @@ -1905,13 +1923,13 @@ static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush) int interval; HWND hwnd;
- if (!(hwnd = NtUserWindowFromDC( draw_hdc ))) interval = 0; - else interval = get_window_swap_interval( hwnd ); + if (!(hwnd = NtUserWindowFromDC( draw_hdc ))) return flush_memory_pbuffer( flush ); + + 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 );
context_sync_drawables( context, draw_hdc, read_hdc ); - if (flush_memory_dc( context, draw_hdc, FALSE, flush )) return TRUE;
if (flush) flush(); if (flush == funcs->p_glFinish) flags |= GL_FLUSH_FINISHED; @@ -1933,11 +1951,13 @@ static BOOL win32u_wglSwapBuffers( HDC hdc ) HWND hwnd; BOOL ret;
- if (!(hwnd = NtUserWindowFromDC( hdc ))) interval = 0; - else interval = get_window_swap_interval( hwnd ); + if (!(hwnd = NtUserWindowFromDC( hdc ))) return flush_memory_pbuffer( funcs->p_glFlush ); + + interval = get_window_swap_interval( hwnd ); + + TRACE( "context %p, hwnd %p, draw_hdc %p, interval %d\n", context, hwnd, draw_hdc, interval );
context_sync_drawables( context, draw_hdc, read_hdc ); - if (flush_memory_dc( context, hdc, FALSE, funcs->p_glFlush )) return TRUE;
if (!(draw = get_dc_opengl_drawable( draw_hdc ))) return FALSE; opengl_drawable_flush( draw, interval, 0 );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/opengl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index ba89eb36d23..092202348a1 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1918,7 +1918,6 @@ static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush) { HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1]; const struct opengl_funcs *funcs = &display_funcs; - struct opengl_drawable *draw; UINT flags = 0; int interval; HWND hwnd; @@ -1933,10 +1932,7 @@ static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush)
if (flush) flush(); if (flush == funcs->p_glFinish) flags |= GL_FLUSH_FINISHED; - - if (!(draw = get_dc_opengl_drawable( draw_hdc ))) return FALSE; - opengl_drawable_flush( draw, interval, flags ); - opengl_drawable_release( draw ); + opengl_drawable_flush( context->draw, interval, flags );
return TRUE; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/opengl32/tests/opengl.c | 2 +- dlls/win32u/opengl.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index 6f73e36732c..f15f456bdfa 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -2749,7 +2749,7 @@ static void test_window_dc(void)
todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); ok_ret( TRUE, wglDeleteContext( ctx ) ); - todo_wine ok_ret( TRUE, SwapBuffers( dc ) ); + ok_ret( TRUE, SwapBuffers( dc ) ); ReleaseDC( window, dc );
DestroyWindow(window); diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 092202348a1..3bbf0d4cb93 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1953,12 +1953,13 @@ static BOOL win32u_wglSwapBuffers( HDC hdc )
TRACE( "context %p, hwnd %p, draw_hdc %p, interval %d\n", context, hwnd, draw_hdc, interval );
- context_sync_drawables( context, draw_hdc, read_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;
- if (!(draw = get_dc_opengl_drawable( draw_hdc ))) return FALSE; opengl_drawable_flush( draw, interval, 0 ); - if (!draw->client) ret = FALSE; /* pbuffer, nothing to do */ - else ret = draw->funcs->swap( draw ); + ret = draw->funcs->swap( draw ); opengl_drawable_release( draw );
return ret;
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 f15f456bdfa..3a2bd15b0b2 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 */